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" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 FILE_PATH_LITERAL("/system/etc/hosts"); | 44 FILE_PATH_LITERAL("/system/etc/hosts"); |
45 #endif | 45 #endif |
46 | 46 |
47 #if defined(OS_IOS) | 47 #if defined(OS_IOS) |
48 | 48 |
49 // There is no public API to watch the DNS configuration on iOS. | 49 // There is no public API to watch the DNS configuration on iOS. |
50 class DnsConfigWatcher { | 50 class DnsConfigWatcher { |
51 public: | 51 public: |
52 typedef base::Callback<void(bool succeeded)> CallbackType; | 52 typedef base::Callback<void(bool succeeded)> CallbackType; |
53 | 53 |
54 bool Watch(const CallbackType& callback) { | 54 bool Watch(const CallbackType& callback) { return false; } |
55 return false; | |
56 } | |
57 }; | 55 }; |
58 | 56 |
59 #elif defined(OS_ANDROID) | 57 #elif defined(OS_ANDROID) |
60 // On Android, assume DNS config may have changed on every network change. | 58 // On Android, assume DNS config may have changed on every network change. |
61 class DnsConfigWatcher : public NetworkChangeNotifier::NetworkChangeObserver { | 59 class DnsConfigWatcher : public NetworkChangeNotifier::NetworkChangeObserver { |
62 public: | 60 public: |
63 DnsConfigWatcher() { | 61 DnsConfigWatcher() { NetworkChangeNotifier::AddNetworkChangeObserver(this); } |
64 NetworkChangeNotifier::AddNetworkChangeObserver(this); | |
65 } | |
66 | 62 |
67 virtual ~DnsConfigWatcher() { | 63 virtual ~DnsConfigWatcher() { |
68 NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | 64 NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
69 } | 65 } |
70 | 66 |
71 bool Watch(const base::Callback<void(bool succeeded)>& callback) { | 67 bool Watch(const base::Callback<void(bool succeeded)>& callback) { |
72 callback_ = callback; | 68 callback_ = callback; |
73 return true; | 69 return true; |
74 } | 70 } |
75 | 71 |
76 virtual void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) | 72 virtual void OnNetworkChanged( |
77 OVERRIDE { | 73 NetworkChangeNotifier::ConnectionType type) OVERRIDE { |
78 if (!callback_.is_null() && type != NetworkChangeNotifier::CONNECTION_NONE) | 74 if (!callback_.is_null() && type != NetworkChangeNotifier::CONNECTION_NONE) |
79 callback_.Run(true); | 75 callback_.Run(true); |
80 } | 76 } |
81 | 77 |
82 private: | 78 private: |
83 base::Callback<void(bool succeeded)> callback_; | 79 base::Callback<void(bool succeeded)> callback_; |
84 }; | 80 }; |
85 #elif !defined(OS_MACOSX) | 81 #elif !defined(OS_MACOSX) |
86 // DnsConfigWatcher for OS_MACOSX is in dns_config_watcher_mac.{hh,cc}. | 82 // DnsConfigWatcher for OS_MACOSX is in dns_config_watcher_mac.{hh,cc}. |
87 | 83 |
88 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> | 84 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> |
89 #define _PATH_RESCONF "/etc/resolv.conf" | 85 #define _PATH_RESCONF "/etc/resolv.conf" |
90 #endif | 86 #endif |
91 | 87 |
92 static const base::FilePath::CharType* kFilePathConfig = | 88 static const base::FilePath::CharType* kFilePathConfig = |
93 FILE_PATH_LITERAL(_PATH_RESCONF); | 89 FILE_PATH_LITERAL(_PATH_RESCONF); |
94 | 90 |
95 class DnsConfigWatcher { | 91 class DnsConfigWatcher { |
96 public: | 92 public: |
97 typedef base::Callback<void(bool succeeded)> CallbackType; | 93 typedef base::Callback<void(bool succeeded)> CallbackType; |
98 | 94 |
99 bool Watch(const CallbackType& callback) { | 95 bool Watch(const CallbackType& callback) { |
100 callback_ = callback; | 96 callback_ = callback; |
101 return watcher_.Watch(base::FilePath(kFilePathConfig), false, | 97 return watcher_.Watch( |
102 base::Bind(&DnsConfigWatcher::OnCallback, | 98 base::FilePath(kFilePathConfig), |
103 base::Unretained(this))); | 99 false, |
| 100 base::Bind(&DnsConfigWatcher::OnCallback, base::Unretained(this))); |
104 } | 101 } |
105 | 102 |
106 private: | 103 private: |
107 void OnCallback(const base::FilePath& path, bool error) { | 104 void OnCallback(const base::FilePath& path, bool error) { |
108 callback_.Run(!error); | 105 callback_.Run(!error); |
109 } | 106 } |
110 | 107 |
111 base::FilePathWatcher watcher_; | 108 base::FilePathWatcher watcher_; |
112 CallbackType callback_; | 109 CallbackType callback_; |
113 }; | 110 }; |
(...skipping 13 matching lines...) Expand all Loading... |
127 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; | 124 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; |
128 } | 125 } |
129 #else // all other OS_POSIX | 126 #else // all other OS_POSIX |
130 struct __res_state res; | 127 struct __res_state res; |
131 memset(&res, 0, sizeof(res)); | 128 memset(&res, 0, sizeof(res)); |
132 if (res_ninit(&res) == 0) { | 129 if (res_ninit(&res) == 0) { |
133 result = ConvertResStateToDnsConfig(res, config); | 130 result = ConvertResStateToDnsConfig(res, config); |
134 } else { | 131 } else { |
135 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; | 132 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; |
136 } | 133 } |
137 // Prefer res_ndestroy where available. | 134 // Prefer res_ndestroy where available. |
138 #if defined(OS_MACOSX) || defined(OS_FREEBSD) | 135 #if defined(OS_MACOSX) || defined(OS_FREEBSD) |
139 res_ndestroy(&res); | 136 res_ndestroy(&res); |
140 #else | 137 #else |
141 res_nclose(&res); | 138 res_nclose(&res); |
142 #endif | 139 #endif |
143 #endif | 140 #endif |
144 | 141 |
145 #if defined(OS_MACOSX) && !defined(OS_IOS) | 142 #if defined(OS_MACOSX) && !defined(OS_IOS) |
146 ConfigParsePosixResult error = DnsConfigWatcher::CheckDnsConfig(); | 143 ConfigParsePosixResult error = DnsConfigWatcher::CheckDnsConfig(); |
147 switch (error) { | 144 switch (error) { |
(...skipping 14 matching lines...) Expand all Loading... |
162 // Theoretically, this is bad. __system_property_get is not a supported API | 159 // Theoretically, this is bad. __system_property_get is not a supported API |
163 // (but it's currently visible to anyone using Bionic), and the properties | 160 // (but it's currently visible to anyone using Bionic), and the properties |
164 // are implementation details that may disappear in future Android releases. | 161 // are implementation details that may disappear in future Android releases. |
165 // Practically, libcutils provides property_get, which is a public API, and the | 162 // Practically, libcutils provides property_get, which is a public API, and the |
166 // DNS code (and its clients) are already robust against failing to get the DNS | 163 // DNS code (and its clients) are already robust against failing to get the DNS |
167 // config for whatever reason, so the properties can disappear and the world | 164 // config for whatever reason, so the properties can disappear and the world |
168 // won't end. | 165 // won't end. |
169 // TODO(ttuttle): Depend on libcutils, then switch this (and other uses of | 166 // TODO(ttuttle): Depend on libcutils, then switch this (and other uses of |
170 // __system_property_get) to property_get. | 167 // __system_property_get) to property_get. |
171 ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) { | 168 ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) { |
172 std::string dns1_string, dns2_string; | 169 std::string dns1_string, dns2_string; |
173 char property_value[PROP_VALUE_MAX]; | 170 char property_value[PROP_VALUE_MAX]; |
174 __system_property_get("net.dns1", property_value); | 171 __system_property_get("net.dns1", property_value); |
175 dns1_string = property_value; | 172 dns1_string = property_value; |
176 __system_property_get("net.dns2", property_value); | 173 __system_property_get("net.dns2", property_value); |
177 dns2_string = property_value; | 174 dns2_string = property_value; |
178 if (dns1_string.length() == 0 && dns2_string.length() == 0) | 175 if (dns1_string.length() == 0 && dns2_string.length() == 0) |
179 return CONFIG_PARSE_POSIX_NO_NAMESERVERS; | 176 return CONFIG_PARSE_POSIX_NO_NAMESERVERS; |
180 | 177 |
181 IPAddressNumber dns1_number, dns2_number; | 178 IPAddressNumber dns1_number, dns2_number; |
182 bool parsed1 = ParseIPLiteralToNumber(dns1_string, &dns1_number); | 179 bool parsed1 = ParseIPLiteralToNumber(dns1_string, &dns1_number); |
(...skipping 12 matching lines...) Expand all Loading... |
195 | 192 |
196 return CONFIG_PARSE_POSIX_OK; | 193 return CONFIG_PARSE_POSIX_OK; |
197 } | 194 } |
198 #endif | 195 #endif |
199 | 196 |
200 } // namespace | 197 } // namespace |
201 | 198 |
202 class DnsConfigServicePosix::Watcher { | 199 class DnsConfigServicePosix::Watcher { |
203 public: | 200 public: |
204 explicit Watcher(DnsConfigServicePosix* service) | 201 explicit Watcher(DnsConfigServicePosix* service) |
205 : weak_factory_(this), | 202 : weak_factory_(this), service_(service) {} |
206 service_(service) {} | |
207 ~Watcher() {} | 203 ~Watcher() {} |
208 | 204 |
209 bool Watch() { | 205 bool Watch() { |
210 bool success = true; | 206 bool success = true; |
211 if (!config_watcher_.Watch(base::Bind(&Watcher::OnConfigChanged, | 207 if (!config_watcher_.Watch( |
212 base::Unretained(this)))) { | 208 base::Bind(&Watcher::OnConfigChanged, base::Unretained(this)))) { |
213 LOG(ERROR) << "DNS config watch failed to start."; | 209 LOG(ERROR) << "DNS config watch failed to start."; |
214 success = false; | 210 success = false; |
215 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", | 211 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", |
216 DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG, | 212 DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG, |
217 DNS_CONFIG_WATCH_MAX); | 213 DNS_CONFIG_WATCH_MAX); |
218 } | 214 } |
219 if (!hosts_watcher_.Watch(base::FilePath(kFilePathHosts), false, | 215 if (!hosts_watcher_.Watch( |
220 base::Bind(&Watcher::OnHostsChanged, | 216 base::FilePath(kFilePathHosts), |
221 base::Unretained(this)))) { | 217 false, |
| 218 base::Bind(&Watcher::OnHostsChanged, base::Unretained(this)))) { |
222 LOG(ERROR) << "DNS hosts watch failed to start."; | 219 LOG(ERROR) << "DNS hosts watch failed to start."; |
223 success = false; | 220 success = false; |
224 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", | 221 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", |
225 DNS_CONFIG_WATCH_FAILED_TO_START_HOSTS, | 222 DNS_CONFIG_WATCH_FAILED_TO_START_HOSTS, |
226 DNS_CONFIG_WATCH_MAX); | 223 DNS_CONFIG_WATCH_MAX); |
227 } | 224 } |
228 return success; | 225 return success; |
229 } | 226 } |
230 | 227 |
231 private: | 228 private: |
(...skipping 30 matching lines...) Expand all Loading... |
262 explicit ConfigReader(DnsConfigServicePosix* service) | 259 explicit ConfigReader(DnsConfigServicePosix* service) |
263 : service_(service), success_(false) {} | 260 : service_(service), success_(false) {} |
264 | 261 |
265 virtual void DoWork() OVERRIDE { | 262 virtual void DoWork() OVERRIDE { |
266 base::TimeTicks start_time = base::TimeTicks::Now(); | 263 base::TimeTicks start_time = base::TimeTicks::Now(); |
267 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); | 264 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); |
268 switch (result) { | 265 switch (result) { |
269 case CONFIG_PARSE_POSIX_MISSING_OPTIONS: | 266 case CONFIG_PARSE_POSIX_MISSING_OPTIONS: |
270 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS: | 267 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS: |
271 DCHECK(dns_config_.unhandled_options); | 268 DCHECK(dns_config_.unhandled_options); |
272 // Fall through. | 269 // Fall through. |
273 case CONFIG_PARSE_POSIX_OK: | 270 case CONFIG_PARSE_POSIX_OK: |
274 success_ = true; | 271 success_ = true; |
275 break; | 272 break; |
276 default: | 273 default: |
277 success_ = false; | 274 success_ = false; |
278 break; | 275 break; |
279 } | 276 } |
280 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix", | 277 UMA_HISTOGRAM_ENUMERATION( |
281 result, CONFIG_PARSE_POSIX_MAX); | 278 "AsyncDNS.ConfigParsePosix", result, CONFIG_PARSE_POSIX_MAX); |
282 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); | 279 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); |
283 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", | 280 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", |
284 base::TimeTicks::Now() - start_time); | 281 base::TimeTicks::Now() - start_time); |
285 } | 282 } |
286 | 283 |
287 virtual void OnWorkFinished() OVERRIDE { | 284 virtual void OnWorkFinished() OVERRIDE { |
288 DCHECK(!IsCancelled()); | 285 DCHECK(!IsCancelled()); |
289 if (success_) { | 286 if (success_) { |
290 service_->OnConfigRead(dns_config_); | 287 service_->OnConfigRead(dns_config_); |
291 } else { | 288 } else { |
292 LOG(WARNING) << "Failed to read DnsConfig."; | 289 LOG(WARNING) << "Failed to read DnsConfig."; |
293 } | 290 } |
294 } | 291 } |
295 | 292 |
296 private: | 293 private: |
297 virtual ~ConfigReader() {} | 294 virtual ~ConfigReader() {} |
298 | 295 |
299 DnsConfigServicePosix* service_; | 296 DnsConfigServicePosix* service_; |
300 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 297 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
301 DnsConfig dns_config_; | 298 DnsConfig dns_config_; |
302 bool success_; | 299 bool success_; |
303 | 300 |
304 DISALLOW_COPY_AND_ASSIGN(ConfigReader); | 301 DISALLOW_COPY_AND_ASSIGN(ConfigReader); |
305 }; | 302 }; |
306 | 303 |
307 // A SerialWorker that reads the HOSTS file and runs Callback. | 304 // A SerialWorker that reads the HOSTS file and runs Callback. |
308 class DnsConfigServicePosix::HostsReader : public SerialWorker { | 305 class DnsConfigServicePosix::HostsReader : public SerialWorker { |
309 public: | 306 public: |
310 explicit HostsReader(DnsConfigServicePosix* service) | 307 explicit HostsReader(DnsConfigServicePosix* service) |
311 : service_(service), path_(kFilePathHosts), success_(false) {} | 308 : service_(service), path_(kFilePathHosts), success_(false) {} |
312 | 309 |
313 private: | 310 private: |
314 virtual ~HostsReader() {} | 311 virtual ~HostsReader() {} |
315 | 312 |
316 virtual void DoWork() OVERRIDE { | 313 virtual void DoWork() OVERRIDE { |
317 base::TimeTicks start_time = base::TimeTicks::Now(); | 314 base::TimeTicks start_time = base::TimeTicks::Now(); |
318 success_ = ParseHostsFile(path_, &hosts_); | 315 success_ = ParseHostsFile(path_, &hosts_); |
319 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); | 316 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); |
320 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", | 317 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", |
321 base::TimeTicks::Now() - start_time); | 318 base::TimeTicks::Now() - start_time); |
(...skipping 11 matching lines...) Expand all Loading... |
333 const base::FilePath path_; | 330 const base::FilePath path_; |
334 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 331 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
335 DnsHosts hosts_; | 332 DnsHosts hosts_; |
336 bool success_; | 333 bool success_; |
337 | 334 |
338 DISALLOW_COPY_AND_ASSIGN(HostsReader); | 335 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
339 }; | 336 }; |
340 | 337 |
341 DnsConfigServicePosix::DnsConfigServicePosix() | 338 DnsConfigServicePosix::DnsConfigServicePosix() |
342 : config_reader_(new ConfigReader(this)), | 339 : config_reader_(new ConfigReader(this)), |
343 hosts_reader_(new HostsReader(this)) {} | 340 hosts_reader_(new HostsReader(this)) { |
| 341 } |
344 | 342 |
345 DnsConfigServicePosix::~DnsConfigServicePosix() { | 343 DnsConfigServicePosix::~DnsConfigServicePosix() { |
346 config_reader_->Cancel(); | 344 config_reader_->Cancel(); |
347 hosts_reader_->Cancel(); | 345 hosts_reader_->Cancel(); |
348 } | 346 } |
349 | 347 |
350 void DnsConfigServicePosix::ReadNow() { | 348 void DnsConfigServicePosix::ReadNow() { |
351 config_reader_->WorkNow(); | 349 config_reader_->WorkNow(); |
352 hosts_reader_->WorkNow(); | 350 hosts_reader_->WorkNow(); |
353 } | 351 } |
354 | 352 |
355 bool DnsConfigServicePosix::StartWatching() { | 353 bool DnsConfigServicePosix::StartWatching() { |
356 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 | 354 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 |
357 watcher_.reset(new Watcher(this)); | 355 watcher_.reset(new Watcher(this)); |
358 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", DNS_CONFIG_WATCH_STARTED, | 356 UMA_HISTOGRAM_ENUMERATION( |
359 DNS_CONFIG_WATCH_MAX); | 357 "AsyncDNS.WatchStatus", DNS_CONFIG_WATCH_STARTED, DNS_CONFIG_WATCH_MAX); |
360 return watcher_->Watch(); | 358 return watcher_->Watch(); |
361 } | 359 } |
362 | 360 |
363 void DnsConfigServicePosix::OnConfigChanged(bool succeeded) { | 361 void DnsConfigServicePosix::OnConfigChanged(bool succeeded) { |
364 InvalidateConfig(); | 362 InvalidateConfig(); |
365 if (succeeded) { | 363 if (succeeded) { |
366 config_reader_->WorkNow(); | 364 config_reader_->WorkNow(); |
367 } else { | 365 } else { |
368 LOG(ERROR) << "DNS config watch failed."; | 366 LOG(ERROR) << "DNS config watch failed."; |
369 set_watch_failed(true); | 367 set_watch_failed(true); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 IPEndPoint ipe; | 402 IPEndPoint ipe; |
405 if (!ipe.FromSockAddr( | 403 if (!ipe.FromSockAddr( |
406 reinterpret_cast<const struct sockaddr*>(&addresses[i]), | 404 reinterpret_cast<const struct sockaddr*>(&addresses[i]), |
407 sizeof addresses[i])) { | 405 sizeof addresses[i])) { |
408 return CONFIG_PARSE_POSIX_BAD_ADDRESS; | 406 return CONFIG_PARSE_POSIX_BAD_ADDRESS; |
409 } | 407 } |
410 dns_config->nameservers.push_back(ipe); | 408 dns_config->nameservers.push_back(ipe); |
411 } | 409 } |
412 #elif defined(OS_LINUX) | 410 #elif defined(OS_LINUX) |
413 COMPILE_ASSERT(arraysize(res.nsaddr_list) >= MAXNS && | 411 COMPILE_ASSERT(arraysize(res.nsaddr_list) >= MAXNS && |
414 arraysize(res._u._ext.nsaddrs) >= MAXNS, | 412 arraysize(res._u._ext.nsaddrs) >= MAXNS, |
415 incompatible_libresolv_res_state); | 413 incompatible_libresolv_res_state); |
416 DCHECK_LE(res.nscount, MAXNS); | 414 DCHECK_LE(res.nscount, MAXNS); |
417 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|. | 415 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|. |
418 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|, | 416 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|, |
419 // but we have to combine the two arrays ourselves. | 417 // but we have to combine the two arrays ourselves. |
420 for (int i = 0; i < res.nscount; ++i) { | 418 for (int i = 0; i < res.nscount; ++i) { |
421 IPEndPoint ipe; | 419 IPEndPoint ipe; |
422 const struct sockaddr* addr = NULL; | 420 const struct sockaddr* addr = NULL; |
423 size_t addr_len = 0; | 421 size_t addr_len = 0; |
424 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend. | 422 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 #endif // !defined(OS_ANDROID) | 487 #endif // !defined(OS_ANDROID) |
490 | 488 |
491 } // namespace internal | 489 } // namespace internal |
492 | 490 |
493 // static | 491 // static |
494 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 492 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
495 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); | 493 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); |
496 } | 494 } |
497 | 495 |
498 } // namespace net | 496 } // namespace net |
OLD | NEW |