Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(91)

Side by Side Diff: net/dns/host_resolver_impl.cc

Issue 19498003: [net/dns] Perform A/AAAA queries for AF_UNSPEC resolutions in parallel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: sync Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/dns/host_resolver_impl.h ('k') | net/dns/host_resolver_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 952 matching lines...) Expand 10 before | Expand all | Expand 10 after
963 963
964 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob); 964 DISALLOW_COPY_AND_ASSIGN(LoopbackProbeJob);
965 }; 965 };
966 966
967 //----------------------------------------------------------------------------- 967 //-----------------------------------------------------------------------------
968 968
969 // Resolves the hostname using DnsTransaction. 969 // Resolves the hostname using DnsTransaction.
970 // TODO(szym): This could be moved to separate source file as well. 970 // TODO(szym): This could be moved to separate source file as well.
971 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> { 971 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
972 public: 972 public:
973 typedef base::Callback<void(int net_error, 973 class Delegate {
974 const AddressList& addr_list, 974 public:
975 base::TimeDelta ttl)> Callback; 975 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
976 int net_error,
977 const AddressList& addr_list,
978 base::TimeDelta ttl) = 0;
979
980 // Called when the first of two jobs succeeds. If the first completed
981 // transaction fails, this is not called. Also not called when the DnsTask
982 // only needs to run one transaction.
983 virtual void OnFirstDnsTransactionComplete() = 0;
984
985 protected:
986 Delegate() {}
987 virtual ~Delegate() {}
988 };
976 989
977 DnsTask(DnsClient* client, 990 DnsTask(DnsClient* client,
978 const Key& key, 991 const Key& key,
979 const Callback& callback, 992 Delegate* delegate,
980 const BoundNetLog& job_net_log) 993 const BoundNetLog& job_net_log)
981 : client_(client), 994 : client_(client),
982 family_(key.address_family), 995 key_(key),
983 callback_(callback), 996 delegate_(delegate),
984 net_log_(job_net_log) { 997 net_log_(job_net_log),
998 num_completed_transactions_(0),
999 task_start_time_(base::TimeTicks::Now()) {
985 DCHECK(client); 1000 DCHECK(client);
986 DCHECK(!callback.is_null()); 1001 DCHECK(delegate_);
1002 }
987 1003
988 // If unspecified, do IPv4 first, because suffix search will be faster. 1004 bool needs_two_transactions() const {
989 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ? 1005 return key_.address_family == ADDRESS_FAMILY_UNSPECIFIED;
990 dns_protocol::kTypeAAAA : 1006 }
991 dns_protocol::kTypeA; 1007
992 transaction_ = client_->GetTransactionFactory()->CreateTransaction( 1008 bool needs_another_transaction() const {
993 key.hostname, 1009 return needs_two_transactions() && !transaction_aaaa_;
994 qtype, 1010 }
1011
1012 void StartFirstTransaction() {
1013 DCHECK_EQ(0u, num_completed_transactions_);
1014 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
1015 if (key_.address_family == ADDRESS_FAMILY_IPV6) {
1016 StartAAAA();
1017 } else {
1018 StartA();
1019 }
1020 }
1021
1022 void StartSecondTransaction() {
1023 DCHECK(needs_two_transactions());
1024 StartAAAA();
1025 }
1026
1027 private:
1028 void StartA() {
1029 DCHECK(!transaction_a_);
1030 DCHECK_NE(ADDRESS_FAMILY_IPV6, key_.address_family);
1031 transaction_a_ = CreateTransaction(ADDRESS_FAMILY_IPV4);
1032 transaction_a_->Start();
1033 }
1034
1035 void StartAAAA() {
1036 DCHECK(!transaction_aaaa_);
1037 DCHECK_NE(ADDRESS_FAMILY_IPV4, key_.address_family);
1038 transaction_aaaa_ = CreateTransaction(ADDRESS_FAMILY_IPV6);
1039 transaction_aaaa_->Start();
1040 }
1041
1042 scoped_ptr<DnsTransaction> CreateTransaction(AddressFamily family) {
1043 DCHECK_NE(ADDRESS_FAMILY_UNSPECIFIED, family);
1044 return client_->GetTransactionFactory()->CreateTransaction(
1045 key_.hostname,
1046 family == ADDRESS_FAMILY_IPV6 ? dns_protocol::kTypeAAAA :
1047 dns_protocol::kTypeA,
995 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), 1048 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
996 true /* first_query */, base::TimeTicks::Now()), 1049 base::TimeTicks::Now()),
997 net_log_); 1050 net_log_);
998 } 1051 }
999 1052
1000 void Start() { 1053 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, 1054 DnsTransaction* transaction,
1009 int net_error, 1055 int net_error,
1010 const DnsResponse* response) { 1056 const DnsResponse* response) {
1011 DCHECK(transaction); 1057 DCHECK(transaction);
1012 base::TimeDelta duration = base::TimeTicks::Now() - start_time; 1058 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) { 1059 if (net_error != OK) {
1015 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration); 1060 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration);
1016 OnFailure(net_error, DnsResponse::DNS_PARSE_OK); 1061 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1017 return; 1062 return;
1018 } 1063 }
1019 1064
1020 CHECK(response);
1021 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration); 1065 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration);
1022 switch (transaction->GetType()) { 1066 switch (transaction->GetType()) {
1023 case dns_protocol::kTypeA: 1067 case dns_protocol::kTypeA:
1024 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration); 1068 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_A", duration);
1025 break; 1069 break;
1026 case dns_protocol::kTypeAAAA: 1070 case dns_protocol::kTypeAAAA:
1027 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration); 1071 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration);
1028 break; 1072 break;
1029 } 1073 }
1074
1030 AddressList addr_list; 1075 AddressList addr_list;
1031 base::TimeDelta ttl; 1076 base::TimeDelta ttl;
1032 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl); 1077 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1033 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", 1078 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1034 result, 1079 result,
1035 DnsResponse::DNS_PARSE_RESULT_MAX); 1080 DnsResponse::DNS_PARSE_RESULT_MAX);
1036 if (result != DnsResponse::DNS_PARSE_OK) { 1081 if (result != DnsResponse::DNS_PARSE_OK) {
1037 // Fail even if the other query succeeds. 1082 // Fail even if the other query succeeds.
1038 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result); 1083 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1039 return; 1084 return;
1040 } 1085 }
1041 1086
1042 bool needs_sort = false; 1087 ++num_completed_transactions_;
1043 if (first_query) { 1088 if (num_completed_transactions_ == 1) {
1044 DCHECK(client_->GetConfig()) << 1089 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 { 1090 } else {
1062 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_); 1091 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 } 1092 }
1072 1093
1073 if (addr_list.empty()) { 1094 if (transaction->GetType() == dns_protocol::kTypeA) {
1074 // TODO(szym): Don't fallback to ProcTask in this case. 1095 DCHECK_EQ(transaction_a_.get(), transaction);
1075 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); 1096 // Place IPv4 addresses after IPv6.
szym 2013/08/22 15:50:07 Oh oh... Looks like we missed handling of this cas
1097 addr_list_.insert(addr_list_.end(), addr_list.begin(), addr_list.end());
1098 } else {
1099 DCHECK_EQ(transaction_aaaa_.get(), transaction);
1100 // Place IPv6 addresses before IPv4.
1101 addr_list_.insert(addr_list_.begin(), addr_list.begin(), addr_list.end());
1102 }
1103
1104 if (needs_two_transactions() && num_completed_transactions_ == 1) {
1105 // No need to repeat the suffix search.
1106 key_.hostname = transaction->GetHostname();
1107 delegate_->OnFirstDnsTransactionComplete();
1076 return; 1108 return;
1077 } 1109 }
1078 1110
szym 2013/08/22 15:50:07 if (addr_list.empty()) { OnFailure(ERR_NAME_NOT_
1079 if (needs_sort) { 1111 // If there are multiple addresses, and at least one is IPv6, need to sort
1080 // Sort could complete synchronously. 1112 // them. Note that IPv6 addresses are always put before IPv4 ones, so it's
1113 // sufficient to just check the family of the first address.
1114 if (addr_list_.size() > 1 &&
1115 addr_list_[0].GetFamily() == ADDRESS_FAMILY_IPV6) {
1116 // Sort addresses if needed. Sort could complete synchronously.
1081 client_->GetAddressSorter()->Sort( 1117 client_->GetAddressSorter()->Sort(
1082 addr_list, 1118 addr_list_,
1083 base::Bind(&DnsTask::OnSortComplete, 1119 base::Bind(&DnsTask::OnSortComplete,
1084 AsWeakPtr(), 1120 AsWeakPtr(),
1085 base::TimeTicks::Now(), 1121 base::TimeTicks::Now()));
1086 ttl));
1087 } else { 1122 } else {
1088 OnSuccess(addr_list, ttl); 1123 OnSuccess(addr_list_);
1089 } 1124 }
1090 } 1125 }
1091 1126
1092 void OnSortComplete(base::TimeTicks start_time, 1127 void OnSortComplete(base::TimeTicks start_time,
1093 base::TimeDelta ttl,
1094 bool success, 1128 bool success,
1095 const AddressList& addr_list) { 1129 const AddressList& addr_list) {
1096 if (!success) { 1130 if (!success) {
1097 DNS_HISTOGRAM("AsyncDNS.SortFailure", 1131 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1098 base::TimeTicks::Now() - start_time); 1132 base::TimeTicks::Now() - start_time);
1099 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK); 1133 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1100 return; 1134 return;
1101 } 1135 }
1102 1136
1103 DNS_HISTOGRAM("AsyncDNS.SortSuccess", 1137 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1104 base::TimeTicks::Now() - start_time); 1138 base::TimeTicks::Now() - start_time);
1105 1139
1106 // AddressSorter prunes unusable destinations. 1140 // AddressSorter prunes unusable destinations.
1107 if (addr_list.empty()) { 1141 if (addr_list.empty()) {
1108 LOG(WARNING) << "Address list empty after RFC3484 sort"; 1142 LOG(WARNING) << "Address list empty after RFC3484 sort";
1109 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK); 1143 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1110 return; 1144 return;
1111 } 1145 }
1112 1146
1113 OnSuccess(addr_list, ttl); 1147 OnSuccess(addr_list);
1114 } 1148 }
1115 1149
1116 void OnFailure(int net_error, DnsResponse::Result result) { 1150 void OnFailure(int net_error, DnsResponse::Result result) {
1117 DCHECK_NE(OK, net_error); 1151 DCHECK_NE(OK, net_error);
1118 net_log_.EndEvent( 1152 net_log_.EndEvent(
1119 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1153 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1120 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); 1154 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
1121 callback_.Run(net_error, AddressList(), base::TimeDelta()); 1155 delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(),
1156 base::TimeDelta());
1122 } 1157 }
1123 1158
1124 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) { 1159 void OnSuccess(const AddressList& addr_list) {
1125 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1160 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1126 addr_list.CreateNetLogCallback()); 1161 addr_list.CreateNetLogCallback());
1127 callback_.Run(OK, addr_list, ttl); 1162 delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_);
1128 } 1163 }
1129 1164
1130 DnsClient* client_; 1165 DnsClient* client_;
1131 AddressFamily family_; 1166 Key key_;
1167
1132 // The listener to the results of this DnsTask. 1168 // The listener to the results of this DnsTask.
1133 Callback callback_; 1169 Delegate* delegate_;
1134 const BoundNetLog net_log_; 1170 const BoundNetLog net_log_;
1135 1171
1136 scoped_ptr<DnsTransaction> transaction_; 1172 scoped_ptr<DnsTransaction> transaction_a_;
1173 scoped_ptr<DnsTransaction> transaction_aaaa_;
1137 1174
1138 // Results from the first transaction. Used only if |family_| is unspecified. 1175 unsigned num_completed_transactions_;
1139 AddressList first_addr_list_; 1176
1140 base::TimeDelta first_ttl_; 1177 // These are updated as each transaction completes.
1178 base::TimeDelta ttl_;
1179 // IPv6 addresses must appear first in the list.
1180 AddressList addr_list_;
1181
1182 base::TimeTicks task_start_time_;
1141 1183
1142 DISALLOW_COPY_AND_ASSIGN(DnsTask); 1184 DISALLOW_COPY_AND_ASSIGN(DnsTask);
1143 }; 1185 };
1144 1186
1145 //----------------------------------------------------------------------------- 1187 //-----------------------------------------------------------------------------
1146 1188
1147 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. 1189 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
1148 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { 1190 class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
1191 public HostResolverImpl::DnsTask::Delegate {
1149 public: 1192 public:
1150 // Creates new job for |key| where |request_net_log| is bound to the 1193 // Creates new job for |key| where |request_net_log| is bound to the
1151 // request that spawned it. 1194 // request that spawned it.
1152 Job(const base::WeakPtr<HostResolverImpl>& resolver, 1195 Job(const base::WeakPtr<HostResolverImpl>& resolver,
1153 const Key& key, 1196 const Key& key,
1154 RequestPriority priority, 1197 RequestPriority priority,
1155 const BoundNetLog& request_net_log) 1198 const BoundNetLog& request_net_log)
1156 : resolver_(resolver), 1199 : resolver_(resolver),
1157 key_(key), 1200 key_(key),
1158 priority_tracker_(priority), 1201 priority_tracker_(priority),
1159 had_non_speculative_request_(false), 1202 had_non_speculative_request_(false),
1160 had_dns_config_(false), 1203 had_dns_config_(false),
1204 num_occupied_job_slots_(0),
1161 dns_task_error_(OK), 1205 dns_task_error_(OK),
1162 creation_time_(base::TimeTicks::Now()), 1206 creation_time_(base::TimeTicks::Now()),
1163 priority_change_time_(creation_time_), 1207 priority_change_time_(creation_time_),
1164 net_log_(BoundNetLog::Make(request_net_log.net_log(), 1208 net_log_(BoundNetLog::Make(request_net_log.net_log(),
1165 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) { 1209 NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
1166 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB); 1210 request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
1167 1211
1168 net_log_.BeginEvent( 1212 net_log_.BeginEvent(
1169 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 1213 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1170 base::Bind(&NetLogJobCreationCallback, 1214 base::Bind(&NetLogJobCreationCallback,
1171 request_net_log.source(), 1215 request_net_log.source(),
1172 &key_.hostname)); 1216 &key_.hostname));
1173 } 1217 }
1174 1218
1175 virtual ~Job() { 1219 virtual ~Job() {
1176 if (is_running()) { 1220 if (is_running()) {
1177 // |resolver_| was destroyed with this Job still in flight. 1221 // |resolver_| was destroyed with this Job still in flight.
1178 // Clean-up, record in the log, but don't run any callbacks. 1222 // Clean-up, record in the log, but don't run any callbacks.
1179 if (is_proc_running()) { 1223 if (is_proc_running()) {
1180 proc_task_->Cancel(); 1224 proc_task_->Cancel();
1181 proc_task_ = NULL; 1225 proc_task_ = NULL;
1182 } 1226 }
1183 // Clean up now for nice NetLog. 1227 // Clean up now for nice NetLog.
1184 dns_task_.reset(NULL); 1228 KillDnsTask();
1185 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, 1229 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
1186 ERR_ABORTED); 1230 ERR_ABORTED);
1187 } else if (is_queued()) { 1231 } else if (is_queued()) {
1188 // |resolver_| was destroyed without running this Job. 1232 // |resolver_| was destroyed without running this Job.
1189 // TODO(szym): is there any benefit in having this distinction? 1233 // TODO(szym): is there any benefit in having this distinction?
1190 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 1234 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
1191 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB); 1235 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB);
1192 } 1236 }
1193 // else CompleteRequests logged EndEvent. 1237 // else CompleteRequests logged EndEvent.
1194 1238
1195 // Log any remaining Requests as cancelled. 1239 // Log any remaining Requests as cancelled.
1196 for (RequestsList::const_iterator it = requests_.begin(); 1240 for (RequestsList::const_iterator it = requests_.begin();
1197 it != requests_.end(); ++it) { 1241 it != requests_.end(); ++it) {
1198 Request* req = *it; 1242 Request* req = *it;
1199 if (req->was_canceled()) 1243 if (req->was_canceled())
1200 continue; 1244 continue;
1201 DCHECK_EQ(this, req->job()); 1245 DCHECK_EQ(this, req->job());
1202 LogCancelRequest(req->source_net_log(), req->request_net_log(), 1246 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1203 req->info()); 1247 req->info());
1204 } 1248 }
1205 } 1249 }
1206 1250
1207 // Add this job to the dispatcher. 1251 // Add this job to the dispatcher. If "at_head" is true, adds at the front
1208 void Schedule() { 1252 // of the queue.
1209 handle_ = resolver_->dispatcher_.Add(this, priority()); 1253 void Schedule(bool at_head) {
1254 DCHECK(!is_queued());
1255 PrioritizedDispatcher::Handle handle;
1256 if (!at_head) {
1257 handle = resolver_->dispatcher_.Add(this, priority());
1258 } else {
1259 handle = resolver_->dispatcher_.AddAtHead(this, priority());
1260 }
1261 // The dispatcher could have started |this| in the above call to Add, which
1262 // could have called Schedule again. In that case |handle| will be null,
1263 // but |handle_| may have been set by the other nested call to Schedule.
1264 if (!handle.is_null()) {
1265 DCHECK(handle_.is_null());
1266 handle_ = handle;
1267 }
1210 } 1268 }
1211 1269
1212 void AddRequest(scoped_ptr<Request> req) { 1270 void AddRequest(scoped_ptr<Request> req) {
1213 DCHECK_EQ(key_.hostname, req->info().hostname()); 1271 DCHECK_EQ(key_.hostname, req->info().hostname());
1214 1272
1215 req->set_job(this); 1273 req->set_job(this);
1216 priority_tracker_.Add(req->priority()); 1274 priority_tracker_.Add(req->priority());
1217 1275
1218 req->request_net_log().AddEvent( 1276 req->request_net_log().AddEvent(
1219 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH, 1277 NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1267 // Called from AbortAllInProgressJobs. Completes all requests and destroys 1325 // Called from AbortAllInProgressJobs. Completes all requests and destroys
1268 // the job. This currently assumes the abort is due to a network change. 1326 // the job. This currently assumes the abort is due to a network change.
1269 void Abort() { 1327 void Abort() {
1270 DCHECK(is_running()); 1328 DCHECK(is_running());
1271 CompleteRequestsWithError(ERR_NETWORK_CHANGED); 1329 CompleteRequestsWithError(ERR_NETWORK_CHANGED);
1272 } 1330 }
1273 1331
1274 // If DnsTask present, abort it and fall back to ProcTask. 1332 // If DnsTask present, abort it and fall back to ProcTask.
1275 void AbortDnsTask() { 1333 void AbortDnsTask() {
1276 if (dns_task_) { 1334 if (dns_task_) {
1277 dns_task_.reset(); 1335 KillDnsTask();
1278 dns_task_error_ = OK; 1336 dns_task_error_ = OK;
1279 StartProcTask(); 1337 StartProcTask();
1280 } 1338 }
1281 } 1339 }
1282 1340
1283 // Called by HostResolverImpl when this job is evicted due to queue overflow. 1341 // Called by HostResolverImpl when this job is evicted due to queue overflow.
1284 // Completes all requests and destroys the job. 1342 // Completes all requests and destroys the job.
1285 void OnEvicted() { 1343 void OnEvicted() {
1286 DCHECK(!is_running()); 1344 DCHECK(!is_running());
1287 DCHECK(is_queued()); 1345 DCHECK(is_queued());
(...skipping 28 matching lines...) Expand all
1316 1374
1317 bool is_queued() const { 1375 bool is_queued() const {
1318 return !handle_.is_null(); 1376 return !handle_.is_null();
1319 } 1377 }
1320 1378
1321 bool is_running() const { 1379 bool is_running() const {
1322 return is_dns_running() || is_proc_running(); 1380 return is_dns_running() || is_proc_running();
1323 } 1381 }
1324 1382
1325 private: 1383 private:
1384 void KillDnsTask() {
1385 if (dns_task_) {
1386 ReduceToOneJobSlot();
1387 dns_task_.reset();
1388 }
1389 }
1390
1391 // Reduce the number of job slots occupied and queued in the dispatcher
1392 // to one. If the second Job slot is queued in the dispatcher, cancels the
1393 // queued job. Otherwise, the second Job has been started by the
1394 // PrioritizedDispatcher, so signals it is complete.
1395 void ReduceToOneJobSlot() {
1396 DCHECK_GE(num_occupied_job_slots_, 1u);
1397 if (is_queued()) {
1398 resolver_->dispatcher_.Cancel(handle_);
1399 handle_.Reset();
1400 } else if (num_occupied_job_slots_ > 1) {
1401 resolver_->dispatcher_.OnJobFinished();
1402 --num_occupied_job_slots_;
1403 }
1404 DCHECK_EQ(1u, num_occupied_job_slots_);
1405 }
1406
1326 void UpdatePriority() { 1407 void UpdatePriority() {
1327 if (is_queued()) { 1408 if (is_queued()) {
1328 if (priority() != static_cast<RequestPriority>(handle_.priority())) 1409 if (priority() != static_cast<RequestPriority>(handle_.priority()))
1329 priority_change_time_ = base::TimeTicks::Now(); 1410 priority_change_time_ = base::TimeTicks::Now();
1330 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority()); 1411 handle_ = resolver_->dispatcher_.ChangePriority(handle_, priority());
1331 } 1412 }
1332 } 1413 }
1333 1414
1334 AddressList MakeAddressListForRequest(const AddressList& list) const { 1415 AddressList MakeAddressListForRequest(const AddressList& list) const {
1335 if (requests_.empty()) 1416 if (requests_.empty())
1336 return list; 1417 return list;
1337 return AddressList::CopyWithPort(list, requests_.front()->info().port()); 1418 return AddressList::CopyWithPort(list, requests_.front()->info().port());
1338 } 1419 }
1339 1420
1340 // PriorityDispatch::Job: 1421 // PriorityDispatch::Job:
1341 virtual void Start() OVERRIDE { 1422 virtual void Start() OVERRIDE {
1423 DCHECK_LE(num_occupied_job_slots_, 1u);
1424
1425 handle_.Reset();
1426 ++num_occupied_job_slots_;
1427
1428 if (num_occupied_job_slots_ == 2) {
1429 StartSecondDnsTransaction();
1430 return;
1431 }
1432
1342 DCHECK(!is_running()); 1433 DCHECK(!is_running());
1343 handle_.Reset();
1344 1434
1345 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED); 1435 net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
1346 1436
1347 had_dns_config_ = resolver_->HaveDnsConfig(); 1437 had_dns_config_ = resolver_->HaveDnsConfig();
1348 1438
1349 base::TimeTicks now = base::TimeTicks::Now(); 1439 base::TimeTicks now = base::TimeTicks::Now();
1350 base::TimeDelta queue_time = now - creation_time_; 1440 base::TimeDelta queue_time = now - creation_time_;
1351 base::TimeDelta queue_time_after_change = now - priority_change_time_; 1441 base::TimeDelta queue_time_after_change = now - priority_change_time_;
1352 1442
1353 if (had_dns_config_) { 1443 if (had_dns_config_) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1437 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); 1527 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
1438 1528
1439 // Don't store the |ttl| in cache since it's not obtained from the server. 1529 // Don't store the |ttl| in cache since it's not obtained from the server.
1440 CompleteRequests( 1530 CompleteRequests(
1441 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)), 1531 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list)),
1442 ttl); 1532 ttl);
1443 } 1533 }
1444 1534
1445 void StartDnsTask() { 1535 void StartDnsTask() {
1446 DCHECK(resolver_->HaveDnsConfig()); 1536 DCHECK(resolver_->HaveDnsConfig());
1447 base::TimeTicks start_time = base::TimeTicks::Now(); 1537 dns_task_.reset(new DnsTask(resolver_->dns_client_.get(), key_, this,
1448 dns_task_.reset(new DnsTask( 1538 net_log_));
1449 resolver_->dns_client_.get(),
1450 key_,
1451 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time),
1452 net_log_));
1453 1539
1454 dns_task_->Start(); 1540 dns_task_->StartFirstTransaction();
1541 // Schedule a second transaction, if needed.
1542 if (dns_task_->needs_two_transactions())
1543 Schedule(true);
1544 }
1545
1546 void StartSecondDnsTransaction() {
1547 DCHECK(dns_task_->needs_two_transactions());
1548 dns_task_->StartSecondTransaction();
1455 } 1549 }
1456 1550
1457 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be 1551 // 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, 1552 // 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. 1553 // so we use it as indicator whether Job is still valid.
1460 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task, 1554 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task,
1461 base::TimeDelta duration, 1555 base::TimeDelta duration,
1462 int net_error) { 1556 int net_error) {
1463 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration); 1557 DNS_HISTOGRAM("AsyncDNS.ResolveFail", duration);
1464 1558
1465 if (dns_task == NULL) 1559 if (dns_task == NULL)
1466 return; 1560 return;
1467 1561
1468 dns_task_error_ = net_error; 1562 dns_task_error_ = net_error;
1469 1563
1470 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. 1564 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1471 // http://crbug.com/117655 1565 // http://crbug.com/117655
1472 1566
1473 // TODO(szym): Some net errors indicate lack of connectivity. Starting 1567 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1474 // ProcTask in that case is a waste of time. 1568 // ProcTask in that case is a waste of time.
1475 if (resolver_->fallback_to_proctask_) { 1569 if (resolver_->fallback_to_proctask_) {
1476 dns_task_.reset(); 1570 KillDnsTask();
1477 StartProcTask(); 1571 StartProcTask();
1478 } else { 1572 } else {
1479 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL); 1573 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
1480 CompleteRequestsWithError(net_error); 1574 CompleteRequestsWithError(net_error);
1481 } 1575 }
1482 } 1576 }
1483 1577
1484 // Called by DnsTask when it completes. 1578
1485 void OnDnsTaskComplete(base::TimeTicks start_time, 1579 // HostResolverImpl::DnsTask::Delegate implementation:
1486 int net_error, 1580
1487 const AddressList& addr_list, 1581 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
1488 base::TimeDelta ttl) { 1582 int net_error,
1583 const AddressList& addr_list,
1584 base::TimeDelta ttl) OVERRIDE {
1489 DCHECK(is_dns_running()); 1585 DCHECK(is_dns_running());
1490 1586
1491 base::TimeDelta duration = base::TimeTicks::Now() - start_time; 1587 base::TimeDelta duration = base::TimeTicks::Now() - start_time;
1492 if (net_error != OK) { 1588 if (net_error != OK) {
1493 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error); 1589 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, net_error);
1494 return; 1590 return;
1495 } 1591 }
1496 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration); 1592 DNS_HISTOGRAM("AsyncDNS.ResolveSuccess", duration);
1497 // Log DNS lookups based on |address_family|. 1593 // Log DNS lookups based on |address_family|.
1498 switch(key_.address_family) { 1594 switch(key_.address_family) {
(...skipping 14 matching lines...) Expand all
1513 resolver_->OnDnsTaskResolve(OK); 1609 resolver_->OnDnsTaskResolve(OK);
1514 1610
1515 base::TimeDelta bounded_ttl = 1611 base::TimeDelta bounded_ttl =
1516 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds)); 1612 std::max(ttl, base::TimeDelta::FromSeconds(kMinimumTTLSeconds));
1517 1613
1518 CompleteRequests( 1614 CompleteRequests(
1519 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl), 1615 HostCache::Entry(net_error, MakeAddressListForRequest(addr_list), ttl),
1520 bounded_ttl); 1616 bounded_ttl);
1521 } 1617 }
1522 1618
1619 virtual void OnFirstDnsTransactionComplete() OVERRIDE {
1620 DCHECK(dns_task_->needs_two_transactions());
1621 DCHECK_EQ(dns_task_->needs_another_transaction(), is_queued());
1622 // No longer need to occupy two dispatcher slots.
1623 ReduceToOneJobSlot();
1624
1625 // We already have a job slot at the dispatcher, so if the second
1626 // transaction hasn't started, reuse it now instead of waiting in the queue
1627 // for the second slot.
1628 if (dns_task_->needs_another_transaction())
1629 dns_task_->StartSecondTransaction();
1630 }
1631
1523 // Performs Job's last rites. Completes all Requests. Deletes this. 1632 // Performs Job's last rites. Completes all Requests. Deletes this.
1524 void CompleteRequests(const HostCache::Entry& entry, 1633 void CompleteRequests(const HostCache::Entry& entry,
1525 base::TimeDelta ttl) { 1634 base::TimeDelta ttl) {
1526 CHECK(resolver_.get()); 1635 CHECK(resolver_.get());
1527 1636
1528 // This job must be removed from resolver's |jobs_| now to make room for a 1637 // 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 1638 // 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 1639 // to spawn one. Consequently, the job deletes itself when CompleteRequests
1531 // is done. 1640 // is done.
1532 scoped_ptr<Job> self_deleter(this); 1641 scoped_ptr<Job> self_deleter(this);
1533 1642
1534 resolver_->RemoveJob(this); 1643 resolver_->RemoveJob(this);
1535 1644
1536 if (is_running()) { 1645 if (is_running()) {
1537 DCHECK(!is_queued());
1538 if (is_proc_running()) { 1646 if (is_proc_running()) {
1647 DCHECK(!is_queued());
1539 proc_task_->Cancel(); 1648 proc_task_->Cancel();
1540 proc_task_ = NULL; 1649 proc_task_ = NULL;
1541 } 1650 }
1542 dns_task_.reset(); 1651 KillDnsTask();
1543 1652
1544 // Signal dispatcher that a slot has opened. 1653 // Signal dispatcher that a slot has opened.
1545 resolver_->dispatcher_.OnJobFinished(); 1654 resolver_->dispatcher_.OnJobFinished();
1546 } else if (is_queued()) { 1655 } else if (is_queued()) {
1547 resolver_->dispatcher_.Cancel(handle_); 1656 resolver_->dispatcher_.Cancel(handle_);
1548 handle_.Reset(); 1657 handle_.Reset();
1549 } 1658 }
1550 1659
1551 if (num_active_requests() == 0) { 1660 if (num_active_requests() == 0) {
1552 net_log_.AddEvent(NetLog::TYPE_CANCELLED); 1661 net_log_.AddEvent(NetLog::TYPE_CANCELLED);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1626 Key key_; 1735 Key key_;
1627 1736
1628 // Tracks the highest priority across |requests_|. 1737 // Tracks the highest priority across |requests_|.
1629 PriorityTracker priority_tracker_; 1738 PriorityTracker priority_tracker_;
1630 1739
1631 bool had_non_speculative_request_; 1740 bool had_non_speculative_request_;
1632 1741
1633 // Distinguishes measurements taken while DnsClient was fully configured. 1742 // Distinguishes measurements taken while DnsClient was fully configured.
1634 bool had_dns_config_; 1743 bool had_dns_config_;
1635 1744
1745 // Number of slots occupied by this Job in resolver's PrioritizedDispatcher.
1746 unsigned num_occupied_job_slots_;
1747
1636 // Result of DnsTask. 1748 // Result of DnsTask.
1637 int dns_task_error_; 1749 int dns_task_error_;
1638 1750
1639 const base::TimeTicks creation_time_; 1751 const base::TimeTicks creation_time_;
1640 base::TimeTicks priority_change_time_; 1752 base::TimeTicks priority_change_time_;
1641 1753
1642 BoundNetLog net_log_; 1754 BoundNetLog net_log_;
1643 1755
1644 // Resolves the host using a HostResolverProc. 1756 // Resolves the host using a HostResolverProc.
1645 scoped_refptr<ProcTask> proc_task_; 1757 scoped_refptr<ProcTask> proc_task_;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1713 { 1825 {
1714 DnsConfig dns_config; 1826 DnsConfig dns_config;
1715 NetworkChangeNotifier::GetDnsConfig(&dns_config); 1827 NetworkChangeNotifier::GetDnsConfig(&dns_config);
1716 received_dns_config_ = dns_config.IsValid(); 1828 received_dns_config_ = dns_config.IsValid();
1717 } 1829 }
1718 1830
1719 fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial(); 1831 fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial();
1720 } 1832 }
1721 1833
1722 HostResolverImpl::~HostResolverImpl() { 1834 HostResolverImpl::~HostResolverImpl() {
1723 // This will also cancel all outstanding requests. 1835 // Prevent the dispatcher from starting new jobs.
1836 dispatcher_.Disable();
1837 // It's now safe for Jobs to call KillDsnTask on destruction, because
1838 // OnJobComplete will not start any new jobs.
1724 STLDeleteValues(&jobs_); 1839 STLDeleteValues(&jobs_);
1725 1840
1726 NetworkChangeNotifier::RemoveIPAddressObserver(this); 1841 NetworkChangeNotifier::RemoveIPAddressObserver(this);
1727 NetworkChangeNotifier::RemoveDNSObserver(this); 1842 NetworkChangeNotifier::RemoveDNSObserver(this);
1728 } 1843 }
1729 1844
1730 void HostResolverImpl::SetMaxQueuedJobs(size_t value) { 1845 void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
1731 DCHECK_EQ(0u, dispatcher_.num_queued_jobs()); 1846 DCHECK_EQ(0u, dispatcher_.num_queued_jobs());
1732 DCHECK_GT(value, 0u); 1847 DCHECK_GT(value, 0u);
1733 max_queued_jobs_ = value; 1848 max_queued_jobs_ = value;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1766 } 1881 }
1767 1882
1768 // Next we need to attach our request to a "job". This job is responsible for 1883 // Next we need to attach our request to a "job". This job is responsible for
1769 // calling "getaddrinfo(hostname)" on a worker thread. 1884 // calling "getaddrinfo(hostname)" on a worker thread.
1770 1885
1771 JobMap::iterator jobit = jobs_.find(key); 1886 JobMap::iterator jobit = jobs_.find(key);
1772 Job* job; 1887 Job* job;
1773 if (jobit == jobs_.end()) { 1888 if (jobit == jobs_.end()) {
1774 job = 1889 job =
1775 new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log); 1890 new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log);
1776 job->Schedule(); 1891 job->Schedule(false);
1777 1892
1778 // Check for queue overflow. 1893 // Check for queue overflow.
1779 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) { 1894 if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
1780 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest()); 1895 Job* evicted = static_cast<Job*>(dispatcher_.EvictOldestLowest());
1781 DCHECK(evicted); 1896 DCHECK(evicted);
1782 evicted->OnEvicted(); // Deletes |evicted|. 1897 evicted->OnEvicted(); // Deletes |evicted|.
1783 if (evicted == job) { 1898 if (evicted == job) {
1784 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE; 1899 rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
1785 LogFinishRequest(source_net_log, request_net_log, info, rv); 1900 LogFinishRequest(source_net_log, request_net_log, info, rv);
1786 return rv; 1901 return rv;
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
2063 Job* job = it->second; 2178 Job* job = it->second;
2064 if (job->is_running()) { 2179 if (job->is_running()) {
2065 jobs_to_abort.push_back(job); 2180 jobs_to_abort.push_back(job);
2066 jobs_.erase(it++); 2181 jobs_.erase(it++);
2067 } else { 2182 } else {
2068 DCHECK(job->is_queued()); 2183 DCHECK(job->is_queued());
2069 ++it; 2184 ++it;
2070 } 2185 }
2071 } 2186 }
2072 2187
2073 // Check if no dispatcher slots leaked out.
2074 DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
2075
2076 // Life check to bail once |this| is deleted. 2188 // Life check to bail once |this| is deleted.
2077 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr(); 2189 base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
2078 2190
2079 // Then Abort them. 2191 // Then Abort them.
2080 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) { 2192 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) {
2081 jobs_to_abort[i]->Abort(); 2193 jobs_to_abort[i]->Abort();
2082 jobs_to_abort[i] = NULL; 2194 jobs_to_abort[i] = NULL;
2083 } 2195 }
2084 } 2196 }
2085 2197
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
2197 } 2309 }
2198 DnsConfig dns_config; 2310 DnsConfig dns_config;
2199 NetworkChangeNotifier::GetDnsConfig(&dns_config); 2311 NetworkChangeNotifier::GetDnsConfig(&dns_config);
2200 dns_client_->SetConfig(dns_config); 2312 dns_client_->SetConfig(dns_config);
2201 num_dns_failures_ = 0; 2313 num_dns_failures_ = 0;
2202 if (dns_config.IsValid()) 2314 if (dns_config.IsValid())
2203 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true); 2315 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
2204 } 2316 }
2205 2317
2206 } // namespace net 2318 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/host_resolver_impl.h ('k') | net/dns/host_resolver_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698