| 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/dns_config_service_posix.h" | 5 #include "net/dns/dns_config_service_posix.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/files/file_path_watcher.h" |
| 11 #include "base/file_path.h" | 12 #include "base/file_path.h" |
| 12 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 15 #include "base/time.h" | 16 #include "base/time.h" |
| 16 #include "net/base/ip_endpoint.h" | 17 #include "net/base/ip_endpoint.h" |
| 17 #include "net/base/net_util.h" | 18 #include "net/base/net_util.h" |
| 18 #include "net/dns/dns_hosts.h" | 19 #include "net/dns/dns_hosts.h" |
| 19 #include "net/dns/dns_protocol.h" | 20 #include "net/dns/dns_protocol.h" |
| 21 #include "net/dns/notify_watcher_mac.h" |
| 20 #include "net/dns/serial_worker.h" | 22 #include "net/dns/serial_worker.h" |
| 21 | 23 |
| 22 namespace net { | 24 namespace net { |
| 23 | 25 |
| 24 #if !defined(OS_ANDROID) | 26 #if !defined(OS_ANDROID) |
| 25 namespace internal { | 27 namespace internal { |
| 26 | 28 |
| 27 namespace { | 29 namespace { |
| 28 | 30 |
| 31 const FilePath::CharType* kFilePathHosts = FILE_PATH_LITERAL("/etc/hosts"); |
| 32 |
| 33 #if defined(OS_MACOSX) |
| 34 // From 10.7.3 configd-395.10/dnsinfo/dnsinfo.h |
| 35 static const char* kDnsNotifyKey = |
| 36 "com.apple.system.SystemConfiguration.dns_configuration"; |
| 37 |
| 38 class ConfigWatcher { |
| 39 public: |
| 40 bool Watch(const base::Callback<void(bool succeeded)>& callback) { |
| 41 return watcher_.Watch(kDnsNotifyKey, callback); |
| 42 } |
| 43 |
| 44 private: |
| 45 NotifyWatcherMac watcher_; |
| 46 }; |
| 47 #else |
| 48 |
| 29 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> | 49 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> |
| 30 #define _PATH_RESCONF "/etc/resolv.conf" | 50 #define _PATH_RESCONF "/etc/resolv.conf" |
| 31 #endif | 51 #endif |
| 32 | 52 |
| 33 const FilePath::CharType* kFilePathHosts = FILE_PATH_LITERAL("/etc/hosts"); | 53 static const FilePath::CharType* kFilePathConfig = |
| 54 FILE_PATH_LITERAL(_PATH_RESCONF); |
| 55 |
| 56 class ConfigWatcher { |
| 57 public: |
| 58 typedef base::Callback<void(bool succeeded)> CallbackType; |
| 59 |
| 60 bool Watch(const CallbackType& callback) { |
| 61 callback_ = callback; |
| 62 return watcher_.Watch(FilePath(kFilePathConfig), |
| 63 base::Bind(&ConfigWatcher::OnCallback, |
| 64 base::Unretained(this))); |
| 65 } |
| 66 |
| 67 private: |
| 68 void OnCallback(const FilePath& path, bool error) { |
| 69 callback_.Run(!error); |
| 70 } |
| 71 |
| 72 base::files::FilePathWatcher watcher_; |
| 73 CallbackType callback_; |
| 74 }; |
| 75 #endif |
| 34 | 76 |
| 35 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) { | 77 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) { |
| 36 ConfigParsePosixResult result; | 78 ConfigParsePosixResult result; |
| 37 #if defined(OS_OPENBSD) | 79 #if defined(OS_OPENBSD) |
| 38 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. | 80 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. |
| 39 // res_init behaves the same way. | 81 // res_init behaves the same way. |
| 40 memset(&_res, 0, sizeof(_res)); | 82 memset(&_res, 0, sizeof(_res)); |
| 41 if (res_init() == 0) { | 83 if (res_init() == 0) { |
| 42 result = ConvertResStateToDnsConfig(_res, config); | 84 result = ConvertResStateToDnsConfig(_res, config); |
| 43 } else { | 85 } else { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 56 res_ndestroy(&res); | 98 res_ndestroy(&res); |
| 57 #else | 99 #else |
| 58 res_nclose(&res); | 100 res_nclose(&res); |
| 59 #endif | 101 #endif |
| 60 #endif | 102 #endif |
| 61 // Override timeout value to match default setting on Windows. | 103 // Override timeout value to match default setting on Windows. |
| 62 config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds); | 104 config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds); |
| 63 return result; | 105 return result; |
| 64 } | 106 } |
| 65 | 107 |
| 108 } // namespace |
| 109 |
| 110 class DnsConfigServicePosix::Watcher { |
| 111 public: |
| 112 explicit Watcher(DnsConfigServicePosix* service) : service_(service) {} |
| 113 ~Watcher() {} |
| 114 |
| 115 bool Watch() { |
| 116 bool success = true; |
| 117 if (!config_watcher_.Watch( |
| 118 base::Bind(&DnsConfigServicePosix::OnConfigChanged, |
| 119 base::Unretained(service_)))) { |
| 120 LOG(ERROR) << "DNS config watch failed to start."; |
| 121 success = false; |
| 122 } |
| 123 if (!hosts_watcher_.Watch(FilePath(kFilePathHosts), |
| 124 base::Bind(&Watcher::OnHostsChanged, |
| 125 base::Unretained(this)))) { |
| 126 LOG(ERROR) << "DNS hosts watch failed to start."; |
| 127 success = false; |
| 128 } |
| 129 return success; |
| 130 } |
| 131 |
| 132 private: |
| 133 void OnHostsChanged(const FilePath& path, bool error) { |
| 134 service_->OnHostsChanged(!error); |
| 135 } |
| 136 |
| 137 DnsConfigServicePosix* service_; |
| 138 ConfigWatcher config_watcher_; |
| 139 base::files::FilePathWatcher hosts_watcher_; |
| 140 |
| 141 DISALLOW_COPY_AND_ASSIGN(Watcher); |
| 142 }; |
| 143 |
| 66 // A SerialWorker that uses libresolv to initialize res_state and converts | 144 // A SerialWorker that uses libresolv to initialize res_state and converts |
| 67 // it to DnsConfig. | 145 // it to DnsConfig. |
| 68 class ConfigReader : public SerialWorker { | 146 class DnsConfigServicePosix::ConfigReader : public SerialWorker { |
| 69 public: | 147 public: |
| 70 typedef base::Callback<void(const DnsConfig& config)> CallbackType; | 148 explicit ConfigReader(DnsConfigServicePosix* service) |
| 71 explicit ConfigReader(const CallbackType& callback) | 149 : service_(service), success_(false) {} |
| 72 : callback_(callback), success_(false) {} | |
| 73 | 150 |
| 74 virtual void DoWork() OVERRIDE { | 151 virtual void DoWork() OVERRIDE { |
| 75 base::TimeTicks start_time = base::TimeTicks::Now(); | 152 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 76 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); | 153 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); |
| 77 success_ = (result == CONFIG_PARSE_POSIX_OK); | 154 success_ = (result == CONFIG_PARSE_POSIX_OK); |
| 78 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix", | 155 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix", |
| 79 result, CONFIG_PARSE_POSIX_MAX); | 156 result, CONFIG_PARSE_POSIX_MAX); |
| 80 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); | 157 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); |
| 81 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", | 158 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", |
| 82 base::TimeTicks::Now() - start_time); | 159 base::TimeTicks::Now() - start_time); |
| 83 } | 160 } |
| 84 | 161 |
| 85 virtual void OnWorkFinished() OVERRIDE { | 162 virtual void OnWorkFinished() OVERRIDE { |
| 86 DCHECK(!IsCancelled()); | 163 DCHECK(!IsCancelled()); |
| 87 if (success_) { | 164 if (success_) { |
| 88 callback_.Run(dns_config_); | 165 service_->OnConfigRead(dns_config_); |
| 89 } else { | 166 } else { |
| 90 LOG(WARNING) << "Failed to read DnsConfig."; | 167 LOG(WARNING) << "Failed to read DnsConfig."; |
| 91 } | 168 } |
| 92 } | 169 } |
| 93 | 170 |
| 94 private: | 171 private: |
| 95 virtual ~ConfigReader() {} | 172 virtual ~ConfigReader() {} |
| 96 | 173 |
| 97 const CallbackType callback_; | 174 DnsConfigServicePosix* service_; |
| 98 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 175 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
| 99 DnsConfig dns_config_; | 176 DnsConfig dns_config_; |
| 100 bool success_; | 177 bool success_; |
| 101 | 178 |
| 102 DISALLOW_COPY_AND_ASSIGN(ConfigReader); | 179 DISALLOW_COPY_AND_ASSIGN(ConfigReader); |
| 103 }; | 180 }; |
| 104 | 181 |
| 105 // A SerialWorker that reads the HOSTS file and runs Callback. | 182 // A SerialWorker that reads the HOSTS file and runs Callback. |
| 106 class HostsReader : public SerialWorker { | 183 class DnsConfigServicePosix::HostsReader : public SerialWorker { |
| 107 public: | 184 public: |
| 108 typedef base::Callback<void(const DnsHosts& hosts)> CallbackType; | 185 explicit HostsReader(DnsConfigServicePosix* service) |
| 109 explicit HostsReader(const CallbackType& callback) | 186 : service_(service), path_(kFilePathHosts), success_(false) {} |
| 110 : path_(kFilePathHosts), callback_(callback), success_(false) {} | |
| 111 | 187 |
| 112 private: | 188 private: |
| 113 virtual ~HostsReader() {} | 189 virtual ~HostsReader() {} |
| 114 | 190 |
| 115 virtual void DoWork() OVERRIDE { | 191 virtual void DoWork() OVERRIDE { |
| 116 base::TimeTicks start_time = base::TimeTicks::Now(); | 192 base::TimeTicks start_time = base::TimeTicks::Now(); |
| 117 success_ = ParseHostsFile(path_, &hosts_); | 193 success_ = ParseHostsFile(path_, &hosts_); |
| 118 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); | 194 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); |
| 119 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", | 195 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", |
| 120 base::TimeTicks::Now() - start_time); | 196 base::TimeTicks::Now() - start_time); |
| 121 } | 197 } |
| 122 | 198 |
| 123 virtual void OnWorkFinished() OVERRIDE { | 199 virtual void OnWorkFinished() OVERRIDE { |
| 124 if (success_) { | 200 if (success_) { |
| 125 callback_.Run(hosts_); | 201 service_->OnHostsRead(hosts_); |
| 126 } else { | 202 } else { |
| 127 LOG(WARNING) << "Failed to read DnsHosts."; | 203 LOG(WARNING) << "Failed to read DnsHosts."; |
| 128 } | 204 } |
| 129 } | 205 } |
| 130 | 206 |
| 207 DnsConfigServicePosix* service_; |
| 131 const FilePath path_; | 208 const FilePath path_; |
| 132 const CallbackType callback_; | 209 const CallbackType callback_; |
| 133 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 210 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
| 134 DnsHosts hosts_; | 211 DnsHosts hosts_; |
| 135 bool success_; | 212 bool success_; |
| 136 | 213 |
| 137 DISALLOW_COPY_AND_ASSIGN(HostsReader); | 214 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
| 138 }; | 215 }; |
| 139 | 216 |
| 140 } // namespace | 217 DnsConfigServicePosix::DnsConfigServicePosix() |
| 141 | 218 : watcher_(new Watcher(this)), |
| 142 DnsConfigServicePosix::DnsConfigServicePosix() { | 219 config_reader_(new ConfigReader(this)), |
| 143 config_reader_ = new ConfigReader( | 220 hosts_reader_(new HostsReader(this)) {} |
| 144 base::Bind(&DnsConfigServicePosix::OnConfigRead, | |
| 145 base::Unretained(this))); | |
| 146 hosts_reader_ = new HostsReader( | |
| 147 base::Bind(&DnsConfigServicePosix::OnHostsRead, | |
| 148 base::Unretained(this))); | |
| 149 } | |
| 150 | 221 |
| 151 DnsConfigServicePosix::~DnsConfigServicePosix() { | 222 DnsConfigServicePosix::~DnsConfigServicePosix() { |
| 152 config_reader_->Cancel(); | 223 config_reader_->Cancel(); |
| 153 hosts_reader_->Cancel(); | 224 hosts_reader_->Cancel(); |
| 154 } | 225 } |
| 155 | 226 |
| 156 void DnsConfigServicePosix::OnDNSChanged(unsigned detail) { | 227 void DnsConfigServicePosix::ReadNow() { |
| 157 if (detail & NetworkChangeNotifier::CHANGE_DNS_WATCH_FAILED) { | 228 config_reader_->WorkNow(); |
| 158 InvalidateConfig(); | 229 hosts_reader_->WorkNow(); |
| 159 InvalidateHosts(); | 230 } |
| 160 // We don't trust a config that we cannot watch in the future. | 231 |
| 161 config_reader_->Cancel(); | 232 bool DnsConfigServicePosix::StartWatching() { |
| 162 hosts_reader_->Cancel(); | 233 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 |
| 163 return; | 234 return watcher_->Watch(); |
| 164 } | 235 } |
| 165 if (detail & NetworkChangeNotifier::CHANGE_DNS_WATCH_STARTED) | 236 |
| 166 detail = ~0; // Assume everything changed. | 237 void DnsConfigServicePosix::OnConfigChanged(bool succeeded) { |
| 167 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) { | 238 InvalidateConfig(); |
| 168 InvalidateConfig(); | 239 if (succeeded) { |
| 169 config_reader_->WorkNow(); | 240 config_reader_->WorkNow(); |
| 170 } | 241 } else { |
| 171 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) { | 242 LOG(ERROR) << "DNS config watch failed."; |
| 172 InvalidateHosts(); | 243 set_watch_failed(true); |
| 173 hosts_reader_->WorkNow(); | |
| 174 } | 244 } |
| 175 } | 245 } |
| 176 | 246 |
| 247 void DnsConfigServicePosix::OnHostsChanged(bool succeeded) { |
| 248 InvalidateHosts(); |
| 249 if (succeeded) { |
| 250 hosts_reader_->WorkNow(); |
| 251 } else { |
| 252 LOG(ERROR) << "DNS hosts watch failed."; |
| 253 set_watch_failed(true); |
| 254 } |
| 255 } |
| 256 |
| 177 ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, | 257 ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, |
| 178 DnsConfig* dns_config) { | 258 DnsConfig* dns_config) { |
| 179 CHECK(dns_config != NULL); | 259 CHECK(dns_config != NULL); |
| 180 if (!(res.options & RES_INIT)) | 260 if (!(res.options & RES_INIT)) |
| 181 return CONFIG_PARSE_POSIX_RES_INIT_UNSET; | 261 return CONFIG_PARSE_POSIX_RES_INIT_UNSET; |
| 182 | 262 |
| 183 dns_config->nameservers.clear(); | 263 dns_config->nameservers.clear(); |
| 184 | 264 |
| 185 #if defined(OS_MACOSX) || defined(OS_FREEBSD) | 265 #if defined(OS_MACOSX) || defined(OS_FREEBSD) |
| 186 union res_sockaddr_union addresses[MAXNS]; | 266 union res_sockaddr_union addresses[MAXNS]; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 356 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 277 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); | 357 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); |
| 278 } | 358 } |
| 279 | 359 |
| 280 #else // defined(OS_ANDROID) | 360 #else // defined(OS_ANDROID) |
| 281 // Android NDK provides only a stub <resolv.h> header. | 361 // Android NDK provides only a stub <resolv.h> header. |
| 282 class StubDnsConfigService : public DnsConfigService { | 362 class StubDnsConfigService : public DnsConfigService { |
| 283 public: | 363 public: |
| 284 StubDnsConfigService() {} | 364 StubDnsConfigService() {} |
| 285 virtual ~StubDnsConfigService() {} | 365 virtual ~StubDnsConfigService() {} |
| 286 virtual void OnDNSChanged(unsigned detail) OVERRIDE {} | 366 private: |
| 367 virtual void ReadNow() OVERRIDE {} |
| 368 virtual bool StartWatching() OVERRIDE { return false; } |
| 287 }; | 369 }; |
| 288 // static | 370 // static |
| 289 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 371 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 290 return scoped_ptr<DnsConfigService>(new StubDnsConfigService()); | 372 return scoped_ptr<DnsConfigService>(new StubDnsConfigService()); |
| 291 } | 373 } |
| 292 #endif | 374 #endif |
| 293 | 375 |
| 294 } // namespace net | 376 } // namespace net |
| OLD | NEW |