| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 // |this| may be deleted inside AbortAllInProgressJobs(). | 2146 // |this| may be deleted inside AbortAllInProgressJobs(). |
| 2053 if (self) | 2147 if (self) |
| 2054 TryServingAllJobsFromHosts(); | 2148 TryServingAllJobsFromHosts(); |
| 2055 } | 2149 } |
| 2056 | 2150 |
| 2057 bool HostResolverImpl::HaveDnsConfig() const { | 2151 bool HostResolverImpl::HaveDnsConfig() const { |
| 2058 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL); | 2152 return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL); |
| 2059 } | 2153 } |
| 2060 | 2154 |
| 2061 } // namespace net | 2155 } // namespace net |
| OLD | NEW |