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

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

Issue 10855179: [net/dns] Resolve AF_UNSPEC on dual-stacked systems. Sort addresses according to RFC3484. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 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
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/base/host_resolver_impl.h" 5 #include "net/base/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 20 matching lines...) Expand all
31 #include "base/utf_string_conversions.h" 31 #include "base/utf_string_conversions.h"
32 #include "base/values.h" 32 #include "base/values.h"
33 #include "net/base/address_family.h" 33 #include "net/base/address_family.h"
34 #include "net/base/address_list.h" 34 #include "net/base/address_list.h"
35 #include "net/base/dns_reloader.h" 35 #include "net/base/dns_reloader.h"
36 #include "net/base/host_port_pair.h" 36 #include "net/base/host_port_pair.h"
37 #include "net/base/host_resolver_proc.h" 37 #include "net/base/host_resolver_proc.h"
38 #include "net/base/net_errors.h" 38 #include "net/base/net_errors.h"
39 #include "net/base/net_log.h" 39 #include "net/base/net_log.h"
40 #include "net/base/net_util.h" 40 #include "net/base/net_util.h"
41 #include "net/dns/address_sorter.h"
41 #include "net/dns/dns_client.h" 42 #include "net/dns/dns_client.h"
42 #include "net/dns/dns_config_service.h" 43 #include "net/dns/dns_config_service.h"
43 #include "net/dns/dns_protocol.h" 44 #include "net/dns/dns_protocol.h"
44 #include "net/dns/dns_response.h" 45 #include "net/dns/dns_response.h"
45 #include "net/dns/dns_transaction.h" 46 #include "net/dns/dns_transaction.h"
46 47
47 #if defined(OS_WIN) 48 #if defined(OS_WIN)
48 #include "net/base/winsock_init.h" 49 #include "net/base/winsock_init.h"
49 #endif 50 #endif
50 51
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK); 603 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
603 StartLookupAttempt(); 604 StartLookupAttempt();
604 } 605 }
605 606
606 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve 607 // Cancels this ProcTask. It will be orphaned. Any outstanding resolve
607 // attempts running on worker threads will continue running. Only once all the 608 // attempts running on worker threads will continue running. Only once all the
608 // attempts complete will the final reference to this ProcTask be released. 609 // attempts complete will the final reference to this ProcTask be released.
609 void Cancel() { 610 void Cancel() {
610 DCHECK(origin_loop_->BelongsToCurrentThread()); 611 DCHECK(origin_loop_->BelongsToCurrentThread());
611 612
612 if (was_canceled()) 613 if (was_canceled() || was_completed())
613 return; 614 return;
614 615
615 callback_.Reset(); 616 callback_.Reset();
616 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK); 617 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_PROC_TASK);
617 } 618 }
618 619
619 void set_had_non_speculative_request() { 620 void set_had_non_speculative_request() {
620 DCHECK(origin_loop_->BelongsToCurrentThread()); 621 DCHECK(origin_loop_->BelongsToCurrentThread());
621 had_non_speculative_request_ = true; 622 had_non_speculative_request_ = true;
622 } 623 }
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
1035 1036
1036 BoundNetLog net_log_; 1037 BoundNetLog net_log_;
1037 1038
1038 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob); 1039 DISALLOW_COPY_AND_ASSIGN(IPv6ProbeJob);
1039 }; 1040 };
1040 1041
1041 //----------------------------------------------------------------------------- 1042 //-----------------------------------------------------------------------------
1042 1043
1043 // Resolves the hostname using DnsTransaction. 1044 // Resolves the hostname using DnsTransaction.
1044 // TODO(szym): This could be moved to separate source file as well. 1045 // TODO(szym): This could be moved to separate source file as well.
1045 class HostResolverImpl::DnsTask { 1046 class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
1046 public: 1047 public:
1047 typedef base::Callback<void(int net_error, 1048 typedef base::Callback<void(int net_error,
1048 const AddressList& addr_list, 1049 const AddressList& addr_list,
1049 base::TimeDelta ttl)> Callback; 1050 base::TimeDelta ttl)> Callback;
1050 1051
1051 DnsTask(DnsTransactionFactory* factory, 1052 DnsTask(DnsClient* client,
1052 const Key& key, 1053 const Key& key,
1053 const Callback& callback, 1054 const Callback& callback,
1054 const BoundNetLog& job_net_log) 1055 const BoundNetLog& job_net_log)
1055 : callback_(callback), net_log_(job_net_log) { 1056 : client_(client),
1056 DCHECK(factory); 1057 family_(key.address_family),
1058 callback_(callback),
1059 net_log_(job_net_log) {
1060 DCHECK(client);
1057 DCHECK(!callback.is_null()); 1061 DCHECK(!callback.is_null());
1058 1062
1059 // For now we treat ADDRESS_FAMILY_UNSPEC as if it was IPV4. 1063 // If unspecified, do IPv4 first, because suffix search will be faster.
1060 uint16 qtype = (key.address_family == ADDRESS_FAMILY_IPV6) 1064 uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ?
1061 ? dns_protocol::kTypeAAAA 1065 dns_protocol::kTypeAAAA :
1062 : dns_protocol::kTypeA; 1066 dns_protocol::kTypeA;
1063 // TODO(szym): Implement "happy eyeballs". 1067 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1064 transaction_ = factory->CreateTransaction(
1065 key.hostname, 1068 key.hostname,
1066 qtype, 1069 qtype,
1067 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this), 1070 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1068 base::TimeTicks::Now()), 1071 true /* first_query */, base::TimeTicks::Now()),
1069 net_log_); 1072 net_log_);
1070 DCHECK(transaction_.get());
1071 } 1073 }
1072 1074
1073 int Start() { 1075 int Start() {
1074 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK); 1076 net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
1075 return transaction_->Start(); 1077 return transaction_->Start();
1076 } 1078 }
1077 1079
1078 void OnTransactionComplete(const base::TimeTicks& start_time, 1080 private:
1081 void OnTransactionComplete(bool first_query,
1082 const base::TimeTicks& start_time,
1079 DnsTransaction* transaction, 1083 DnsTransaction* transaction,
1080 int net_error, 1084 int net_error,
1081 const DnsResponse* response) { 1085 const DnsResponse* response) {
1082 DCHECK(transaction); 1086 DCHECK(transaction);
1083 // Run |callback_| last since the owning Job will then delete this DnsTask. 1087 // Run |callback_| last since the owning Job will then delete this DnsTask.
1084 DnsResponse::Result result = DnsResponse::DNS_SUCCESS; 1088 if (net_error != OK) {
1085 if (net_error == OK) { 1089 DNS_HISTOGRAM("AsyncDNS.TransactionFailure",
1086 CHECK(response);
1087 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1088 base::TimeTicks::Now() - start_time); 1090 base::TimeTicks::Now() - start_time);
1089 AddressList addr_list; 1091 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1090 base::TimeDelta ttl; 1092 return;
1091 result = response->ParseToAddressList(&addr_list, &ttl); 1093 }
1092 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList", 1094
1093 result, 1095 CHECK(response);
1094 DnsResponse::DNS_PARSE_RESULT_MAX); 1096 DNS_HISTOGRAM("AsyncDNS.TransactionSuccess",
1095 if (result == DnsResponse::DNS_SUCCESS) { 1097 base::TimeTicks::Now() - start_time);
1096 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1098 AddressList addr_list;
1097 addr_list.CreateNetLogCallback()); 1099 base::TimeDelta ttl;
1098 callback_.Run(net_error, addr_list, ttl); 1100 DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
1101 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ParseToAddressList",
1102 result,
1103 DnsResponse::DNS_PARSE_RESULT_MAX);
1104 if (result != DnsResponse::DNS_PARSE_OK) {
1105 // Fail even if the other query succeeds.
1106 OnFailure(ERR_DNS_MALFORMED_RESPONSE, result);
1107 return;
1108 }
1109
1110 bool needs_sort = false;
1111 if (first_query) {
1112 DCHECK(client_->GetConfig()) <<
1113 "Transaction should have been aborted when config changed!";
1114 if (family_ == ADDRESS_FAMILY_IPV6) {
1115 needs_sort = (addr_list.size() > 1);
1116 } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
1117 first_addr_list_ = addr_list;
1118 first_ttl_ = ttl;
1119 // Use fully-qualified domain name to avoid search.
1120 transaction_ = client_->GetTransactionFactory()->CreateTransaction(
1121 response->GetDottedName() + ".",
1122 dns_protocol::kTypeAAAA,
1123 base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
1124 false /* first_query */, base::TimeTicks::Now()),
1125 net_log_);
1126 net_error = transaction_->Start();
1127 if (net_error != ERR_IO_PENDING)
1128 OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
1099 return; 1129 return;
1100 } 1130 }
1101 net_error = ERR_DNS_MALFORMED_RESPONSE;
1102 } else { 1131 } else {
1103 DNS_HISTOGRAM("AsyncDNS.TransactionFailure", 1132 DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_);
1133 bool has_ipv6_addresses = !addr_list.empty();
1134 if (!first_addr_list_.empty()) {
1135 ttl = std::min(ttl, first_ttl_);
1136 // Place IPv4 addresses after IPv6.
1137 addr_list.insert(addr_list.end(), first_addr_list_.begin(),
1138 first_addr_list_.end());
1139 }
1140 needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
1141 }
1142
1143 if (addr_list.empty()) {
1144 // TODO(szym): Don't fallback to ProcTask in this case.
1145 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1146 return;
1147 }
1148
1149 if (needs_sort) {
1150 // Sort could complete synchronously.
1151 client_->GetAddressSorter()->Sort(
1152 addr_list,
1153 base::Bind(&DnsTask::OnSortComplete, AsWeakPtr(),
1154 base::TimeTicks::Now(),
1155 ttl));
1156 } else {
1157 OnSuccess(addr_list, ttl);
1158 }
1159 }
1160
1161 void OnSortComplete(base::TimeTicks start_time,
1162 base::TimeDelta ttl,
1163 bool success,
1164 const AddressList& addr_list) {
1165 if (!success) {
1166 DNS_HISTOGRAM("AsyncDNS.SortFailure",
1104 base::TimeTicks::Now() - start_time); 1167 base::TimeTicks::Now() - start_time);
1168 OnFailure(ERR_DNS_SORT_ERROR, DnsResponse::DNS_PARSE_OK);
1169 return;
1105 } 1170 }
1171
1172 DNS_HISTOGRAM("AsyncDNS.SortSuccess",
1173 base::TimeTicks::Now() - start_time);
1174
1175 // AddressSorter prunes unusable destinations.
1176 if (addr_list.empty()) {
1177 LOG(WARNING) << "Address list empty after RFC3484 sort";
1178 OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
1179 return;
1180 }
1181
1182 OnSuccess(addr_list, ttl);
1183 }
1184
1185 void OnFailure(int net_error, DnsResponse::Result result) {
1186 DCHECK_NE(OK, net_error);
1106 net_log_.EndEvent( 1187 net_log_.EndEvent(
1107 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK, 1188 NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1108 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result)); 1189 base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
1109 callback_.Run(net_error, AddressList(), base::TimeDelta()); 1190 callback_.Run(net_error, AddressList(), base::TimeDelta());
1110 } 1191 }
1111 1192
1112 private: 1193 void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) {
1194 net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
1195 addr_list.CreateNetLogCallback());
1196 callback_.Run(OK, addr_list, ttl);
1197 }
1198
1199 DnsClient* client_;
1200 AddressFamily family_;
1113 // The listener to the results of this DnsTask. 1201 // The listener to the results of this DnsTask.
1114 Callback callback_; 1202 Callback callback_;
1115
1116 const BoundNetLog net_log_; 1203 const BoundNetLog net_log_;
1117 1204
1118 scoped_ptr<DnsTransaction> transaction_; 1205 scoped_ptr<DnsTransaction> transaction_;
1206
1207 // Results from the first transaction. Used only if |family_| is unspecified.
1208 AddressList first_addr_list_;
1209 base::TimeDelta first_ttl_;
1210
1211 DISALLOW_COPY_AND_ASSIGN(DnsTask);
1119 }; 1212 };
1120 1213
1121 //----------------------------------------------------------------------------- 1214 //-----------------------------------------------------------------------------
1122 1215
1123 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch. 1216 // Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
1124 class HostResolverImpl::Job : public PrioritizedDispatcher::Job { 1217 class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
1125 public: 1218 public:
1126 // Creates new job for |key| where |request_net_log| is bound to the 1219 // Creates new job for |key| where |request_net_log| is bound to the
1127 // request that spawned it. 1220 // request that spawned it.
1128 Job(HostResolverImpl* resolver, 1221 Job(HostResolverImpl* resolver,
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1207 if (proc_task_) 1300 if (proc_task_)
1208 proc_task_->set_had_non_speculative_request(); 1301 proc_task_->set_had_non_speculative_request();
1209 } 1302 }
1210 1303
1211 requests_.push_back(req.release()); 1304 requests_.push_back(req.release());
1212 1305
1213 UpdatePriority(); 1306 UpdatePriority();
1214 } 1307 }
1215 1308
1216 // Marks |req| as cancelled. If it was the last active Request, also finishes 1309 // Marks |req| as cancelled. If it was the last active Request, also finishes
1217 // this Job marking it either as aborted or cancelled, and deletes it. 1310 // this Job, marking it as cancelled, and deletes it.
1218 void CancelRequest(Request* req) { 1311 void CancelRequest(Request* req) {
1219 DCHECK_EQ(key_.hostname, req->info().hostname()); 1312 DCHECK_EQ(key_.hostname, req->info().hostname());
1220 DCHECK(!req->was_canceled()); 1313 DCHECK(!req->was_canceled());
1221 1314
1222 // Don't remove it from |requests_| just mark it canceled. 1315 // Don't remove it from |requests_| just mark it canceled.
1223 req->MarkAsCanceled(); 1316 req->MarkAsCanceled();
1224 LogCancelRequest(req->source_net_log(), req->request_net_log(), 1317 LogCancelRequest(req->source_net_log(), req->request_net_log(),
1225 req->info()); 1318 req->info());
1226 1319
1227 priority_tracker_.Remove(req->info().priority()); 1320 priority_tracker_.Remove(req->info().priority());
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
1374 kNegativeCacheEntryTTLSeconds); 1467 kNegativeCacheEntryTTLSeconds);
1375 if (net_error == OK) 1468 if (net_error == OK)
1376 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); 1469 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
1377 1470
1378 CompleteRequests(net_error, addr_list, ttl); 1471 CompleteRequests(net_error, addr_list, ttl);
1379 } 1472 }
1380 1473
1381 void StartDnsTask() { 1474 void StartDnsTask() {
1382 DCHECK(resolver_->HaveDnsConfig()); 1475 DCHECK(resolver_->HaveDnsConfig());
1383 dns_task_.reset(new DnsTask( 1476 dns_task_.reset(new DnsTask(
1384 resolver_->dns_client_->GetTransactionFactory(), 1477 resolver_->dns_client_.get(),
1385 key_, 1478 key_,
1386 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)), 1479 base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
1387 net_log_)); 1480 net_log_));
1388 1481
1389 int rv = dns_task_->Start(); 1482 int rv = dns_task_->Start();
1390 if (rv != ERR_IO_PENDING) { 1483 if (rv != ERR_IO_PENDING) {
1391 DCHECK_NE(OK, rv); 1484 DCHECK_NE(OK, rv);
1392 dns_task_error_ = rv; 1485 dns_task_error_ = rv;
1393 dns_task_.reset(); 1486 dns_task_.reset();
1394 StartProcTask(); 1487 StartProcTask();
(...skipping 13 matching lines...) Expand all
1408 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. 1501 // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
1409 // http://crbug.com/117655 1502 // http://crbug.com/117655
1410 1503
1411 // TODO(szym): Some net errors indicate lack of connectivity. Starting 1504 // TODO(szym): Some net errors indicate lack of connectivity. Starting
1412 // ProcTask in that case is a waste of time. 1505 // ProcTask in that case is a waste of time.
1413 StartProcTask(); 1506 StartProcTask();
1414 return; 1507 return;
1415 } 1508 }
1416 1509
1417 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS); 1510 UmaAsyncDnsResolveStatus(RESOLVE_STATUS_DNS_SUCCESS);
1511
1418 CompleteRequests(net_error, addr_list, ttl); 1512 CompleteRequests(net_error, addr_list, ttl);
1419 } 1513 }
1420 1514
1421 // Performs Job's last rites. Completes all Requests. Deletes this. 1515 // Performs Job's last rites. Completes all Requests. Deletes this.
1422 void CompleteRequests(int net_error, 1516 void CompleteRequests(int net_error,
1423 const AddressList& addr_list, 1517 const AddressList& addr_list,
1424 base::TimeDelta ttl) { 1518 base::TimeDelta ttl) {
1425 CHECK(resolver_); 1519 CHECK(resolver_);
1426 1520
1427 // This job must be removed from resolver's |jobs_| now to make room for a 1521 // This job must be removed from resolver's |jobs_| now to make room for a
(...skipping 623 matching lines...) Expand 10 before | Expand all | Expand 10 after
2051 // |this| may be deleted inside AbortAllInProgressJobs(). 2145 // |this| may be deleted inside AbortAllInProgressJobs().
2052 if (self) 2146 if (self)
2053 TryServingAllJobsFromHosts(); 2147 TryServingAllJobsFromHosts();
2054 } 2148 }
2055 2149
2056 bool HostResolverImpl::HaveDnsConfig() const { 2150 bool HostResolverImpl::HaveDnsConfig() const {
2057 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL); 2151 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
2058 } 2152 }
2059 2153
2060 } // namespace net 2154 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698