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 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
959 | 959 |
960 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); | 960 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); |
961 }; | 961 }; |
962 | 962 |
963 //----------------------------------------------------------------------------- | 963 //----------------------------------------------------------------------------- |
964 | 964 |
965 // Resolves the hostname using DnsTransaction. | 965 // Resolves the hostname using DnsTransaction. |
966 // TODO(szym): This could be moved to separate source file as well. | 966 // TODO(szym): This could be moved to separate source file as well. |
967 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { | 967 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { |
968 public: | 968 public: |
969 typedef base::Callback<void(int net_error, | 969 class Delegate { |
970 const AddressList& addr_list, | 970 public: |
971 base::TimeDelta ttl)> Callback; | 971 virtual void OnDnsTaskComplete(base::TimeTicks start_time, |
972 int net_error, | |
973 const AddressList& addr_list, | |
974 base::TimeDelta ttl) = 0; | |
975 | |
976 // Called when the first of two jobs succeeds. If the first completed | |
977 // transaction fails, this is not called. Also not called when the DnsTask | |
978 // only needs to run one transaction. | |
979 virtual void OnFirstDnsTransactionComplete() = 0; | |
980 | |
981 protected: | |
982 Delegate() {} | |
983 virtual ~Delegate() {} | |
984 }; | |
972 | 985 |
973 DnsTask(DnsClient* client, | 986 DnsTask(DnsClient* client, |
974 const Key& key, | 987 const Key& key, |
975 const Callback& callback, | 988 Delegate* delegate, |
976 const BoundNetLog& job_net_log) | 989 const BoundNetLog& job_net_log) |
977 : client_(client), | 990 : client_(client), |
978 family_(key.address_family), | 991 key_(key), |
979 callback_(callback), | 992 delegate_(delegate), |
980 net_log_(job_net_log) { | 993 net_log_(job_net_log), |
994 num_completed_transactions_(0), | |
995 task_start_time_(base::TimeTicks::Now()) { | |
981 DCHECK(client); | 996 DCHECK(client); |
982 DCHECK(!callback.is_null()); | 997 DCHECK(delegate_); |
998 } | |
983 | 999 |
984 // If unspecified, do IPv4 first, because suffix search will be faster. | 1000 bool needs_two_transactions() const { |
985 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ? | 1001 return key_.address_family == ADDRESS_FAMILY_UNSPECIFIED; |
986 dns_protocol::kTypeAAAA : | 1002 } |
987 dns_protocol::kTypeA; | 1003 |
988 transaction_ = client_->GetTransactionFactory()->CreateTransaction( | 1004 void StartFirstTransaction() { |
989 key.hostname, | 1005 DCHECK_EQ(0u, num_completed_transactions_); |
990 qtype, | 1006 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK); |
1007 if (key_.address_family == ADDRESS_FAMILY_IPV6) { | |
1008 StartAAAA(); | |
1009 } else { | |
1010 StartA(); | |
1011 } | |
1012 } | |
1013 | |
1014 void StartSecondTransaction() { | |
1015 DCHECK(needs_two_transactions()); | |
1016 StartAAAA(); | |
1017 } | |
1018 | |
1019 private: | |
1020 void StartA() { | |
1021 DCHECK(!transaction_a_); | |
1022 DCHECK_NE(ADDRESS_FAMILY_IPV6, key_.address_family); | |
1023 transaction_a_ = CreateTransaction(ADDRESS_FAMILY_IPV4); | |
1024 transaction_a_->Start(); | |
1025 } | |
1026 | |
1027 void StartAAAA() { | |
1028 DCHECK(!transaction_aaaa_); | |
1029 DCHECK_NE(ADDRESS_FAMILY_IPV4, key_.address_family); | |
1030 transaction_aaaa_ = CreateTransaction(ADDRESS_FAMILY_IPV6); | |
1031 transaction_aaaa_->Start(); | |
1032 } | |
1033 | |
1034 scoped_ptr<DnsTransaction> CreateTransaction(AddressFamily family) { | |
1035 DCHECK_NE(ADDRESS_FAMILY_UNSPECIFIED, family); | |
1036 return client_->GetTransactionFactory()->CreateTransaction( | |
1037 key_.hostname, | |
1038 family == ADDRESS_FAMILY_IPV6 ? dns_protocol::kTypeAAAA : | |
1039 dns_protocol::kTypeA, | |
991 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), | 1040 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), |
992 true /* first_query */, base::TimeTicks::Now()), | 1041 base::TimeTicks::Now()), |
993 net_log_); | 1042 net_log_); |
994 } | 1043 } |
995 | 1044 |
996 void Start() { | 1045 void OnTransactionComplete(const base::TimeTicks& start_time, |
997 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK); | |
998 transaction_->Start(); | |
999 } | |
1000 | |
1001 private: | |
1002 void OnTransactionComplete(bool first_query, | |
1003 const base::TimeTicks& start_time, | |
1004 DnsTransaction* transaction, | 1046 DnsTransaction* transaction, |
1005 int net_error, | 1047 int net_error, |
1006 const DnsResponse* response) { | 1048 const DnsResponse* response) { |
1007 DCHECK(transaction); | 1049 DCHECK(transaction); |
1008 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | 1050 base::TimeDelta duration = base::TimeTicks::Now() - start_time; |
1009 // Run |callback_| last since the owning Job will then delete this DnsTask. | |
1010 if (net_error != OK) { | 1051 if (net_error != OK) { |
1011 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); | 1052 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); |
1012 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); | 1053 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); |
1013 return; | 1054 return; |
1014 } | 1055 } |
1015 | 1056 |
1016 CHECK(response); | |
1017 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); | 1057 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); |
1018 switch (transaction->GetType()) { | 1058 switch (transaction->GetType()) { |
1019 case dns_protocol::kTypeA: | 1059 case dns_protocol::kTypeA: |
1020 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); | 1060 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); |
1021 break; | 1061 break; |
1022 case dns_protocol::kTypeAAAA: | 1062 case dns_protocol::kTypeAAAA: |
1023 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); | 1063 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); |
1024 break; | 1064 break; |
1025 } | 1065 } |
1066 | |
1026 AddressList addr_list; | 1067 AddressList addr_list; |
1027 base::TimeDelta ttl; | 1068 base::TimeDelta ttl; |
1028 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); | 1069 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); |
1029 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", | 1070 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", |
1030 result, | 1071 result, |
1031 DnsResponse::DNS_PARSE_RESULT_MAX); | 1072 DnsResponse::DNS_PARSE_RESULT_MAX); |
1032 if (result != DnsResponse::DNS_PARSE_OK) { | 1073 if (result != DnsResponse::DNS_PARSE_OK) { |
1033 // Fail even if the other query succeeds. | 1074 // Fail even if the other query succeeds. |
1034 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); | 1075 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); |
1035 return; | 1076 return; |
1036 } | 1077 } |
1037 | 1078 |
1038 bool needs_sort = false; | 1079 ++num_completed_transactions_; |
1039 if (first_query) { | 1080 if (num_completed_transactions_ == 1) { |
1040 DCHECK(client_->GetConfig()) << | 1081 ttl_ = ttl; |
1041 "Transaction should have been aborted when config changed!"; | |
1042 if (family_ == ADDRESS_FAMILY_IPV6) { | |
1043 needs_sort = (addr_list.size() > 1); | |
1044 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) { | |
1045 first_addr_list_ = addr_list; | |
1046 first_ttl_ = ttl; | |
1047 // Use fully-qualified domain name to avoid search. | |
1048 transaction_ = client_->GetTransactionFactory()->CreateTransaction( | |
1049 response->GetDottedName() + ".", | |
1050 dns_protocol::kTypeAAAA, | |
1051 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), | |
1052 false /* first_query */, base::TimeTicks::Now()), | |
1053 net_log_); | |
1054 transaction_->Start(); | |
1055 return; | |
1056 } | |
1057 } else { | 1082 } else { |
1058 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_); | 1083 ttl_ = std::min(ttl_, ttl); |
1059 bool has_ipv6_addresses = !addr_list.empty(); | |
1060 if (!first_addr_list_.empty()) { | |
1061 ttl = std::min(ttl, first_ttl_); | |
1062 // Place IPv4 addresses after IPv6. | |
1063 addr_list.insert(addr_list.end(), first_addr_list_.begin(), | |
1064 first_addr_list_.end()); | |
1065 } | |
1066 needs_sort = (has_ipv6_addresses && addr_list.size() > 1); | |
1067 } | 1084 } |
1068 | 1085 |
1069 if (addr_list.empty()) { | 1086 if (transaction->GetType() == dns_protocol::kTypeA) { |
1070 // TODO(szym): Don't fallback to ProcTask in this case. | 1087 DCHECK_EQ(transaction_a_.get(), transaction); |
1071 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); | 1088 // Place IPv4 addresses after IPv6. |
1089 addr_list_.insert(addr_list_.end(), addr_list.begin(), addr_list.end()); | |
1090 } else { | |
1091 DCHECK_EQ(transaction_aaaa_.get(), transaction); | |
1092 // Place IPv6 addresses before IPv4. | |
1093 addr_list_.insert(addr_list_.begin(), addr_list.begin(), addr_list.end()); | |
1094 } | |
1095 | |
1096 if (needs_two_transactions() && num_completed_transactions_ == 1) { | |
1097 delegate_->OnFirstDnsTransactionComplete(); | |
1072 return; | 1098 return; |
1073 } | 1099 } |
1074 | 1100 |
1075 if (needs_sort) { | 1101 // If there are multiple addresses, and at least one is IPv6, need to sort |
1076 // Sort could complete synchronously. | 1102 // them. Note that IPv6 addresses are always put before IPv4 ones, so it's |
1103 // sufficient to just check the family of the first address. | |
1104 if (addr_list_.size() > 1 && | |
1105 addr_list_[0].GetFamily() == ADDRESS_FAMILY_IPV6) { | |
1106 // Sort addresses if needed. Sort could complete synchronously. | |
1077 client_->GetAddressSorter()->Sort( | 1107 client_->GetAddressSorter()->Sort( |
1078 addr_list, | 1108 addr_list_, |
1079 base::Bind(&DnsTask::OnSortComplete, | 1109 base::Bind(&DnsTask::OnSortComplete, |
1080 AsWeakPtr(), | 1110 AsWeakPtr(), |
1081 base::TimeTicks::Now(), | 1111 base::TimeTicks::Now())); |
1082 ttl)); | |
1083 } else { | 1112 } else { |
1084 OnSuccess(addr_list, ttl); | 1113 OnSuccess(addr_list_); |
1085 } | 1114 } |
1086 } | 1115 } |
1087 | 1116 |
1088 void OnSortComplete(base::TimeTicks start_time, | 1117 void OnSortComplete(base::TimeTicks start_time, |
1089 base::TimeDelta ttl, | |
1090 bool success, | 1118 bool success, |
1091 const AddressList& addr_list) { | 1119 const AddressList& addr_list) { |
1092 if (!success) { | 1120 if (!success) { |
1093 DNS_HISTOGRAM("AsyncDNS.SortFailure", | 1121 DNS_HISTOGRAM("AsyncDNS.SortFailure", |
1094 base::TimeTicks::Now() - start_time); | 1122 base::TimeTicks::Now() - start_time); |
1095 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); | 1123 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); |
1096 return; | 1124 return; |
1097 } | 1125 } |
1098 | 1126 |
1099 DNS_HISTOGRAM("AsyncDNS.SortSuccess", | 1127 DNS_HISTOGRAM("AsyncDNS.SortSuccess", |
1100 base::TimeTicks::Now() - start_time); | 1128 base::TimeTicks::Now() - start_time); |
1101 | 1129 |
1102 // AddressSorter prunes unusable destinations. | 1130 // AddressSorter prunes unusable destinations. |
1103 if (addr_list.empty()) { | 1131 if (addr_list.empty()) { |
1104 LOG(WARNING) << "Address list empty after RFC3484 sort"; | 1132 LOG(WARNING) << "Address list empty after RFC3484 sort"; |
1105 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); | 1133 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); |
1106 return; | 1134 return; |
1107 } | 1135 } |
1108 | 1136 |
1109 OnSuccess(addr_list, ttl); | 1137 OnSuccess(addr_list); |
1110 } | 1138 } |
1111 | 1139 |
1112 void OnFailure(int net_error, DnsResponse::Result result) { | 1140 void OnFailure(int net_error, DnsResponse::Result result) { |
1113 DCHECK_NE(OK, net_error); | 1141 DCHECK_NE(OK, net_error); |
1114 net_log_.EndEvent( | 1142 net_log_.EndEvent( |
1115 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, | 1143 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, |
1116 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); | 1144 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); |
1117 callback_.Run(net_error, AddressList(), base::TimeDelta()); | 1145 delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(), |
1146 base::TimeDelta()); | |
1118 } | 1147 } |
1119 | 1148 |
1120 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) { | 1149 void OnSuccess(const AddressList& addr_list) { |
1121 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, | 1150 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, |
1122 addr_list.CreateNetLogCallback()); | 1151 addr_list.CreateNetLogCallback()); |
1123 callback_.Run(OK, addr_list, ttl); | 1152 delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_); |
1124 } | 1153 } |
1125 | 1154 |
1126 DnsClient* client_; | 1155 DnsClient* client_; |
1127 AddressFamily family_; | 1156 Key key_; |
1157 | |
1128 // The listener to the results of this DnsTask. | 1158 // The listener to the results of this DnsTask. |
1129 Callback callback_; | 1159 Delegate* delegate_; |
1130 const BoundNetLog net_log_; | 1160 const BoundNetLog net_log_; |
1131 | 1161 |
1132 scoped_ptr<DnsTransaction> transaction_; | 1162 scoped_ptr<DnsTransaction> transaction_a_; |
1163 scoped_ptr<DnsTransaction> transaction_aaaa_; | |
1133 | 1164 |
1134 // Results from the first transaction. Used only if |family_| is unspecified. | 1165 // Number of transactions that have started, but not yet completed. |
1135 AddressList first_addr_list_; | 1166 unsigned num_completed_transactions_; |
1136 base::TimeDelta first_ttl_; | 1167 |
1168 // These are updated as each transaction completes. | |
1169 base::TimeDelta ttl_; | |
1170 // IPv6 addresses must appear first in the list. | |
1171 AddressList addr_list_; | |
1172 | |
1173 base::TimeTicks task_start_time_; | |
1137 | 1174 |
1138 DISALLOW_COPY_AND_ASSIGN(DnsTask); | 1175 DISALLOW_COPY_AND_ASSIGN(DnsTask); |
1139 }; | 1176 }; |
1140 | 1177 |
1141 //----------------------------------------------------------------------------- | 1178 //----------------------------------------------------------------------------- |
1142 | 1179 |
1143 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. | 1180 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. |
1144 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { | 1181 class HostResolverImpl::Job : public PrioritizedDispatcher::Job, |
1182 public HostResolverImpl::DnsTask::Delegate { | |
1145 public: | 1183 public: |
1146 // Creates new job for |key| where |request_net_log| is bound to the | 1184 // Creates new job for |key| where |request_net_log| is bound to the |
1147 // request that spawned it. | 1185 // request that spawned it. |
1148 Job(const base::WeakPtr<HostResolverImpl>& resolver, | 1186 Job(const base::WeakPtr<HostResolverImpl>& resolver, |
1149 const Key& key, | 1187 const Key& key, |
1150 RequestPriority priority, | 1188 RequestPriority priority, |
1151 const BoundNetLog& request_net_log) | 1189 const BoundNetLog& request_net_log) |
1152 : resolver_(resolver), | 1190 : resolver_(resolver), |
1153 key_(key), | 1191 key_(key), |
1154 priority_tracker_(priority), | 1192 priority_tracker_(priority), |
1155 had_non_speculative_request_(false), | 1193 had_non_speculative_request_(false), |
1156 had_dns_config_(false), | 1194 had_dns_config_(false), |
1195 num_occupied_job_slots_(0), | |
1157 dns_task_error_(OK), | 1196 dns_task_error_(OK), |
1158 creation_time_(base::TimeTicks::Now()), | 1197 creation_time_(base::TimeTicks::Now()), |
1159 priority_change_time_(creation_time_), | 1198 priority_change_time_(creation_time_), |
1160 net_log_(BoundNetLog::Make(request_net_log.net_log(), | 1199 net_log_(BoundNetLog::Make(request_net_log.net_log(), |
1161 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { | 1200 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { |
1162 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); | 1201 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); |
1163 | 1202 |
1164 net_log_.BeginEvent( | 1203 net_log_.BeginEvent( |
1165 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | 1204 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
1166 base::Bind(&NetLogJobCreationCallback, | 1205 base::Bind(&NetLogJobCreationCallback, |
1167 request_net_log.source(), | 1206 request_net_log.source(), |
1168 &key_.hostname)); | 1207 &key_.hostname)); |
1169 } | 1208 } |
1170 | 1209 |
1171 virtual ~Job() { | 1210 virtual ~Job() { |
1172 if (is_running()) { | 1211 if (is_running()) { |
1173 // |resolver_| was destroyed with this Job still in flight. | 1212 // |resolver_| was destroyed with this Job still in flight. |
1174 // Clean-up, record in the log, but don't run any callbacks. | 1213 // Clean-up, record in the log, but don't run any callbacks. |
1175 if (is_proc_running()) { | 1214 if (is_proc_running()) { |
1176 proc_task_->Cancel(); | 1215 proc_task_->Cancel(); |
1177 proc_task_ = NULL; | 1216 proc_task_ = NULL; |
1178 } | 1217 } |
1179 // Clean up now for nice NetLog. | 1218 // Clean up now for nice NetLog. |
1180 dns_task_.reset(NULL); | 1219 KillDnsTask(); |
1181 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, | 1220 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
1182 ERR_ABORTED); | 1221 ERR_ABORTED); |
1183 } else if (is_queued()) { | 1222 } else if (is_queued()) { |
1184 // |resolver_| was destroyed without running this Job. | 1223 // |resolver_| was destroyed without running this Job. |
1185 // TODO(szym): is there any benefit in having this distinction? | 1224 // TODO(szym): is there any benefit in having this distinction? |
1186 net_log_.AddEvent(NetLog::TYPE_CANCELLED); | 1225 net_log_.AddEvent(NetLog::TYPE_CANCELLED); |
1187 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); | 1226 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); |
1188 } | 1227 } |
1189 // else CompleteRequests logged EndEvent. | 1228 // else CompleteRequests logged EndEvent. |
1190 | 1229 |
1191 // Log any remaining Requests as cancelled. | 1230 // Log any remaining Requests as cancelled. |
1192 for (RequestsList::const_iterator it = requests_.begin(); | 1231 for (RequestsList::const_iterator it = requests_.begin(); |
1193 it != requests_.end(); ++it) { | 1232 it != requests_.end(); ++it) { |
1194 Request* req = *it; | 1233 Request* req = *it; |
1195 if (req->was_canceled()) | 1234 if (req->was_canceled()) |
1196 continue; | 1235 continue; |
1197 DCHECK_EQ(this, req->job()); | 1236 DCHECK_EQ(this, req->job()); |
1198 LogCancelRequest(req->source_net_log(), req->request_net_log(), | 1237 LogCancelRequest(req->source_net_log(), req->request_net_log(), |
1199 req->info()); | 1238 req->info()); |
1200 } | 1239 } |
1201 } | 1240 } |
1202 | 1241 |
1203 // Add this job to the dispatcher. | 1242 // Add this job to the dispatcher. If "at_head" is true, adds at the front |
1204 void Schedule() { | 1243 // of the queue. |
1205 handle_ = resolver_->dispatcher_.Add(this, priority()); | 1244 void Schedule(bool at_head) { |
1245 DCHECK(!is_queued()); | |
1246 PrioritizedDispatcher::Handle handle; | |
1247 if (!at_head) { | |
1248 handle = resolver_->dispatcher_.Add(this, priority()); | |
1249 } else { | |
1250 handle = resolver_->dispatcher_.AddAtHead(this, priority()); | |
mmenke
2013/07/24 18:59:45
There doesn't seem to be a reasonable way to test
| |
1251 } | |
1252 // This test is needed for the case that the dispatcher starts |this| | |
1253 // synchronously, and then |this| adds itself again to the dispatcher, | |
1254 // and the second attempt does not complete synchronously. | |
1255 if (!handle.is_null()) { | |
1256 DCHECK(handle_.is_null()); | |
1257 handle_ = handle; | |
1258 } | |
1206 } | 1259 } |
1207 | 1260 |
1208 void AddRequest(scoped_ptr<Request> req) { | 1261 void AddRequest(scoped_ptr<Request> req) { |
1209 DCHECK_EQ(key_.hostname, req->info().hostname()); | 1262 DCHECK_EQ(key_.hostname, req->info().hostname()); |
1210 | 1263 |
1211 req->set_job(this); | 1264 req->set_job(this); |
1212 priority_tracker_.Add(req->info().priority()); | 1265 priority_tracker_.Add(req->info().priority()); |
1213 | 1266 |
1214 req->request_net_log().AddEvent( | 1267 req->request_net_log().AddEvent( |
1215 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, | 1268 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1264 // Called from AbortAllInProgressJobs. Completes all requests and destroys | 1317 // Called from AbortAllInProgressJobs. Completes all requests and destroys |
1265 // the job. This currently assumes the abort is due to a network change. | 1318 // the job. This currently assumes the abort is due to a network change. |
1266 void Abort() { | 1319 void Abort() { |
1267 DCHECK(is_running()); | 1320 DCHECK(is_running()); |
1268 CompleteRequestsWithError(ERR_NETWORK_CHANGED); | 1321 CompleteRequestsWithError(ERR_NETWORK_CHANGED); |
1269 } | 1322 } |
1270 | 1323 |
1271 // If DnsTask present, abort it and fall back to ProcTask. | 1324 // If DnsTask present, abort it and fall back to ProcTask. |
1272 void AbortDnsTask() { | 1325 void AbortDnsTask() { |
1273 if (dns_task_) { | 1326 if (dns_task_) { |
1274 dns_task_.reset(); | 1327 KillDnsTask(); |
1275 dns_task_error_ = OK; | 1328 dns_task_error_ = OK; |
1276 StartProcTask(); | 1329 StartProcTask(); |
1277 } | 1330 } |
1278 } | 1331 } |
1279 | 1332 |
1280 // Called by HostResolverImpl when this job is evicted due to queue overflow. | 1333 // Called by HostResolverImpl when this job is evicted due to queue overflow. |
1281 // Completes all requests and destroys the job. | 1334 // Completes all requests and destroys the job. |
1282 void OnEvicted() { | 1335 void OnEvicted() { |
1283 DCHECK(!is_running()); | 1336 DCHECK(!is_running()); |
1284 DCHECK(is_queued()); | 1337 DCHECK(is_queued()); |
(...skipping 28 matching lines...) Expand all Loading... | |
1313 | 1366 |
1314 bool is_queued() const { | 1367 bool is_queued() const { |
1315 return !handle_.is_null(); | 1368 return !handle_.is_null(); |
1316 } | 1369 } |
1317 | 1370 |
1318 bool is_running() const { | 1371 bool is_running() const { |
1319 return is_dns_running() || is_proc_running(); | 1372 return is_dns_running() || is_proc_running(); |
1320 } | 1373 } |
1321 | 1374 |
1322 private: | 1375 private: |
1376 void KillDnsTask() { | |
1377 if (dns_task_) { | |
1378 FinishOrCancelSecondDispatcherJob(); | |
1379 dns_task_.reset(); | |
1380 } | |
1381 } | |
1382 | |
1383 // If this task is occupying two slots in the PrioritizedDispatcher, cancels | |
1384 // or finishes the second Job, depending on if its started or not. Otherwise, | |
1385 // does nothing. | |
1386 void FinishOrCancelSecondDispatcherJob() { | |
1387 DCHECK_GE(num_occupied_job_slots_, 1u); | |
1388 if (num_occupied_job_slots_ > 1) { | |
1389 DCHECK(dns_task_->needs_two_transactions()); | |
1390 resolver_->dispatcher_.OnJobFinished(); | |
1391 --num_occupied_job_slots_; | |
1392 } else if (is_queued()) { | |
1393 resolver_->dispatcher_.Cancel(handle_); | |
1394 handle_.Reset(); | |
1395 } | |
1396 DCHECK_EQ(1u, num_occupied_job_slots_); | |
1397 } | |
1398 | |
1323 void UpdatePriority() { | 1399 void UpdatePriority() { |
1324 if (is_queued()) { | 1400 if (is_queued()) { |
1325 if (priority() != static_cast<RequestPriority>(handle_.priority())) | 1401 if (priority() != static_cast<RequestPriority>(handle_.priority())) |
1326 priority_change_time_ = base::TimeTicks::Now(); | 1402 priority_change_time_ = base::TimeTicks::Now(); |
1327 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); | 1403 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); |
1328 } | 1404 } |
1329 } | 1405 } |
1330 | 1406 |
1331 AddressList MakeAddressListForRequest(const AddressList& list) const { | 1407 AddressList MakeAddressListForRequest(const AddressList& list) const { |
1332 if (requests_.empty()) | 1408 if (requests_.empty()) |
1333 return list; | 1409 return list; |
1334 return AddressList::CopyWithPort(list, requests_.front()->info().port()); | 1410 return AddressList::CopyWithPort(list, requests_.front()->info().port()); |
1335 } | 1411 } |
1336 | 1412 |
1337 // PriorityDispatch::Job: | 1413 // PriorityDispatch::Job: |
1338 virtual void Start() OVERRIDE { | 1414 virtual void Start() OVERRIDE { |
1415 DCHECK_LE(num_occupied_job_slots_, 1u); | |
1416 | |
1417 handle_.Reset(); | |
1418 ++num_occupied_job_slots_; | |
1419 | |
1420 if (num_occupied_job_slots_ == 2) { | |
1421 StartSecondDnsTransaction(); | |
1422 return; | |
1423 } | |
1424 | |
1339 DCHECK(!is_running()); | 1425 DCHECK(!is_running()); |
1340 handle_.Reset(); | |
1341 | 1426 |
1342 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); | 1427 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); |
1343 | 1428 |
1344 had_dns_config_ = resolver_->HaveDnsConfig(); | 1429 had_dns_config_ = resolver_->HaveDnsConfig(); |
1345 | 1430 |
1346 base::TimeTicks now = base::TimeTicks::Now(); | 1431 base::TimeTicks now = base::TimeTicks::Now(); |
1347 base::TimeDelta queue_time = now - creation_time_; | 1432 base::TimeDelta queue_time = now - creation_time_; |
1348 base::TimeDelta queue_time_after_change = now - priority_change_time_; | 1433 base::TimeDelta queue_time_after_change = now - priority_change_time_; |
1349 | 1434 |
1350 if (had_dns_config_) { | 1435 if (had_dns_config_) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1432 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); | 1517 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); |
1433 | 1518 |
1434 // Don't store the |ttl| in cache since it's not obtained from the server. | 1519 // Don't store the |ttl| in cache since it's not obtained from the server. |
1435 CompleteRequests( | 1520 CompleteRequests( |
1436 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), | 1521 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), |
1437 ttl); | 1522 ttl); |
1438 } | 1523 } |
1439 | 1524 |
1440 void StartDnsTask() { | 1525 void StartDnsTask() { |
1441 DCHECK(resolver_->HaveDnsConfig()); | 1526 DCHECK(resolver_->HaveDnsConfig()); |
1442 base::TimeTicks start_time = base::TimeTicks::Now(); | 1527 dns_task_.reset(new DnsTask(resolver_->dns_client_.get(), key_, this, |
1443 dns_task_.reset(new DnsTask( | 1528 net_log_)); |
1444 resolver_->dns_client_.get(), | |
1445 key_, | |
1446 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time), | |
1447 net_log_)); | |
1448 | 1529 |
1449 dns_task_->Start(); | 1530 dns_task_->StartFirstTransaction(); |
1531 // Schedule a second transaciton, if needed. | |
1532 if (dns_task_->needs_two_transactions()) | |
1533 Schedule(true); | |
1534 } | |
1535 | |
1536 void StartSecondDnsTransaction() { | |
1537 DCHECK(dns_task_->needs_two_transactions()); | |
1538 dns_task_->StartSecondTransaction(); | |
1450 } | 1539 } |
1451 | 1540 |
1452 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be | 1541 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be |
1453 // deleted before this callback. In this case dns_task is deleted as well, | 1542 // deleted before this callback. In this case dns_task is deleted as well, |
1454 // so we use it as indicator whether Job is still valid. | 1543 // so we use it as indicator whether Job is still valid. |
1455 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, | 1544 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, |
1456 base::TimeDelta duration, | 1545 base::TimeDelta duration, |
1457 int net_error) { | 1546 int net_error) { |
1458 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); | 1547 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); |
1459 | 1548 |
1460 if (dns_task == NULL) | 1549 if (dns_task == NULL) |
1461 return; | 1550 return; |
1462 | 1551 |
1463 dns_task_error_ = net_error; | 1552 dns_task_error_ = net_error; |
1464 | 1553 |
1465 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. | 1554 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. |
1466 // http://crbug.com/117655 | 1555 // http://crbug.com/117655 |
1467 | 1556 |
1468 // TODO(szym): Some net errors indicate lack of connectivity. Starting | 1557 // TODO(szym): Some net errors indicate lack of connectivity. Starting |
1469 // ProcTask in that case is a waste of time. | 1558 // ProcTask in that case is a waste of time. |
1470 if (resolver_->fallback_to_proctask_) { | 1559 if (resolver_->fallback_to_proctask_) { |
1471 dns_task_.reset(); | 1560 KillDnsTask(); |
1472 StartProcTask(); | 1561 StartProcTask(); |
1473 } else { | 1562 } else { |
1474 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); | 1563 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); |
1475 CompleteRequestsWithError(net_error); | 1564 CompleteRequestsWithError(net_error); |
1476 } | 1565 } |
1477 } | 1566 } |
1478 | 1567 |
1479 // Called by DnsTask when it completes. | 1568 |
1480 void OnDnsTaskComplete(base::TimeTicks start_time, | 1569 // HostResolverImpl::DnsTask::Delegate implementation: |
1481 int net_error, | 1570 |
1482 const AddressList& addr_list, | 1571 virtual void OnDnsTaskComplete(base::TimeTicks start_time, |
1483 base::TimeDelta ttl) { | 1572 int net_error, |
1573 const AddressList& addr_list, | |
1574 base::TimeDelta ttl) OVERRIDE { | |
1484 DCHECK(is_dns_running()); | 1575 DCHECK(is_dns_running()); |
1485 | 1576 |
1486 base::TimeDelta duration = base::TimeTicks::Now() - start_time; | 1577 base::TimeDelta duration = base::TimeTicks::Now() - start_time; |
1487 if (net_error != OK) { | 1578 if (net_error != OK) { |
1488 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); | 1579 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); |
1489 return; | 1580 return; |
1490 } | 1581 } |
1491 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); | 1582 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); |
1492 // Log DNS lookups based on |address_family|. | 1583 // Log DNS lookups based on |address_family|. |
1493 switch(key_.address_family) { | 1584 switch(key_.address_family) { |
(...skipping 14 matching lines...) Expand all Loading... | |
1508 resolver_->OnDnsTaskResolve(OK); | 1599 resolver_->OnDnsTaskResolve(OK); |
1509 | 1600 |
1510 base::TimeDelta bounded_ttl = | 1601 base::TimeDelta bounded_ttl = |
1511 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); | 1602 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); |
1512 | 1603 |
1513 CompleteRequests( | 1604 CompleteRequests( |
1514 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), | 1605 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), |
1515 bounded_ttl); | 1606 bounded_ttl); |
1516 } | 1607 } |
1517 | 1608 |
1609 virtual void OnFirstDnsTransactionComplete() OVERRIDE { | |
1610 DCHECK(dns_task_->needs_two_transactions()); | |
1611 // If the second job is still queued, start it now. | |
1612 if (is_queued()) | |
1613 dns_task_->StartSecondTransaction(); | |
1614 FinishOrCancelSecondDispatcherJob(); | |
1615 } | |
1616 | |
1518 // Performs Job's last rites. Completes all Requests. Deletes this. | 1617 // Performs Job's last rites. Completes all Requests. Deletes this. |
1519 void CompleteRequests(const HostCache::Entry& entry, | 1618 void CompleteRequests(const HostCache::Entry& entry, |
1520 base::TimeDelta ttl) { | 1619 base::TimeDelta ttl) { |
1521 CHECK(resolver_.get()); | 1620 CHECK(resolver_.get()); |
1522 | 1621 |
1523 // This job must be removed from resolver's |jobs_| now to make room for a | 1622 // This job must be removed from resolver's |jobs_| now to make room for a |
1524 // new job with the same key in case one of the OnComplete callbacks decides | 1623 // new job with the same key in case one of the OnComplete callbacks decides |
1525 // to spawn one. Consequently, the job deletes itself when CompleteRequests | 1624 // to spawn one. Consequently, the job deletes itself when CompleteRequests |
1526 // is done. | 1625 // is done. |
1527 scoped_ptr<Job> self_deleter(this); | 1626 scoped_ptr<Job> self_deleter(this); |
1528 | 1627 |
1529 resolver_->RemoveJob(this); | 1628 resolver_->RemoveJob(this); |
1530 | 1629 |
1531 if (is_running()) { | 1630 if (is_running()) { |
1532 DCHECK(!is_queued()); | |
1533 if (is_proc_running()) { | 1631 if (is_proc_running()) { |
1632 DCHECK(!is_queued()); | |
1534 proc_task_->Cancel(); | 1633 proc_task_->Cancel(); |
1535 proc_task_ = NULL; | 1634 proc_task_ = NULL; |
1536 } | 1635 } |
1537 dns_task_.reset(); | 1636 KillDnsTask(); |
1538 | 1637 |
1539 // Signal dispatcher that a slot has opened. | 1638 // Signal dispatcher that a slot has opened. |
1540 resolver_->dispatcher_.OnJobFinished(); | 1639 resolver_->dispatcher_.OnJobFinished(); |
1541 } else if (is_queued()) { | 1640 } else if (is_queued()) { |
1542 resolver_->dispatcher_.Cancel(handle_); | 1641 resolver_->dispatcher_.Cancel(handle_); |
1543 handle_.Reset(); | 1642 handle_.Reset(); |
1544 } | 1643 } |
1545 | 1644 |
1546 if (num_active_requests() == 0) { | 1645 if (num_active_requests() == 0) { |
1547 net_log_.AddEvent(NetLog::TYPE_CANCELLED); | 1646 net_log_.AddEvent(NetLog::TYPE_CANCELLED); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1621 Key key_; | 1720 Key key_; |
1622 | 1721 |
1623 // Tracks the highest priority across |requests_|. | 1722 // Tracks the highest priority across |requests_|. |
1624 PriorityTracker priority_tracker_; | 1723 PriorityTracker priority_tracker_; |
1625 | 1724 |
1626 bool had_non_speculative_request_; | 1725 bool had_non_speculative_request_; |
1627 | 1726 |
1628 // Distinguishes measurements taken while DnsClient was fully configured. | 1727 // Distinguishes measurements taken while DnsClient was fully configured. |
1629 bool had_dns_config_; | 1728 bool had_dns_config_; |
1630 | 1729 |
1730 // Number of slots occupied by this Job in resolver's PrioritizedDispatcher. | |
1731 unsigned num_occupied_job_slots_; | |
1732 | |
1631 // Result of DnsTask. | 1733 // Result of DnsTask. |
1632 int dns_task_error_; | 1734 int dns_task_error_; |
1633 | 1735 |
1634 const base::TimeTicks creation_time_; | 1736 const base::TimeTicks creation_time_; |
1635 base::TimeTicks priority_change_time_; | 1737 base::TimeTicks priority_change_time_; |
1636 | 1738 |
1637 BoundNetLog net_log_; | 1739 BoundNetLog net_log_; |
1638 | 1740 |
1639 // Resolves the host using a HostResolverProc. | 1741 // Resolves the host using a HostResolverProc. |
1640 scoped_refptr<ProcTask> proc_task_; | 1742 scoped_refptr<ProcTask> proc_task_; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1760 } | 1862 } |
1761 | 1863 |
1762 // Next we need to attach our request to a "job". This job is responsible for | 1864 // Next we need to attach our request to a "job". This job is responsible for |
1763 // calling "getaddrinfo(hostname)" on a worker thread. | 1865 // calling "getaddrinfo(hostname)" on a worker thread. |
1764 | 1866 |
1765 JobMap::iterator jobit = jobs_.find(key); | 1867 JobMap::iterator jobit = jobs_.find(key); |
1766 Job* job; | 1868 Job* job; |
1767 if (jobit == jobs_.end()) { | 1869 if (jobit == jobs_.end()) { |
1768 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(), | 1870 job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(), |
1769 request_net_log); | 1871 request_net_log); |
1770 job->Schedule(); | 1872 job->Schedule(false); |
1771 | 1873 |
1772 // Check for queue overflow. | 1874 // Check for queue overflow. |
1773 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { | 1875 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { |
1774 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); | 1876 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); |
1775 DCHECK(evicted); | 1877 DCHECK(evicted); |
1776 evicted->OnEvicted(); // Deletes |evicted|. | 1878 evicted->OnEvicted(); // Deletes |evicted|. |
1777 if (evicted == job) { | 1879 if (evicted == job) { |
1778 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; | 1880 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; |
1779 LogFinishRequest(source_net_log, request_net_log, info, rv); | 1881 LogFinishRequest(source_net_log, request_net_log, info, rv); |
1780 return rv; | 1882 return rv; |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2058 Job* job = it->second; | 2160 Job* job = it->second; |
2059 if (job->is_running()) { | 2161 if (job->is_running()) { |
2060 jobs_to_abort.push_back(job); | 2162 jobs_to_abort.push_back(job); |
2061 jobs_.erase(it++); | 2163 jobs_.erase(it++); |
2062 } else { | 2164 } else { |
2063 DCHECK(job->is_queued()); | 2165 DCHECK(job->is_queued()); |
2064 ++it; | 2166 ++it; |
2065 } | 2167 } |
2066 } | 2168 } |
2067 | 2169 |
2068 // Check if no dispatcher slots leaked out. | |
2069 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size()); | |
2070 | |
2071 // Life check to bail once |this| is deleted. | 2170 // Life check to bail once |this| is deleted. |
2072 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); | 2171 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); |
2073 | 2172 |
2074 // Then Abort them. | 2173 // Then Abort them. |
2075 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { | 2174 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { |
2076 jobs_to_abort[i]->Abort(); | 2175 jobs_to_abort[i]->Abort(); |
2077 jobs_to_abort[i] = NULL; | 2176 jobs_to_abort[i] = NULL; |
2078 } | 2177 } |
2079 } | 2178 } |
2080 | 2179 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2192 } | 2291 } |
2193 DnsConfig dns_config; | 2292 DnsConfig dns_config; |
2194 NetworkChangeNotifier::GetDnsConfig(&dns_config); | 2293 NetworkChangeNotifier::GetDnsConfig(&dns_config); |
2195 dns_client_->SetConfig(dns_config); | 2294 dns_client_->SetConfig(dns_config); |
2196 num_dns_failures_ = 0; | 2295 num_dns_failures_ = 0; |
2197 if (dns_config.IsValid()) | 2296 if (dns_config.IsValid()) |
2198 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); | 2297 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); |
2199 } | 2298 } |
2200 | 2299 |
2201 } // namespace net | 2300 } // namespace net |
OLD | NEW |