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