Index: net/dns/dns_config_watcher_mac.cc |
diff --git a/net/dns/dns_config_watcher_mac.cc b/net/dns/dns_config_watcher_mac.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a92db0cf1796ba44adb9cfdb0aa1c462a91ae442 |
--- /dev/null |
+++ b/net/dns/dns_config_watcher_mac.cc |
@@ -0,0 +1,106 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/dns/dns_config_watcher_mac.h" |
+ |
+#include <dlfcn.h> |
+ |
+#include "base/lazy_instance.h" |
+#include "third_party/apple_apsl/dnsinfo.h" |
+ |
+namespace { |
+ |
+// dnsinfo symbols are available via libSystem.dylib, but can also be present in |
+// SystemConfiguration.framework. To avoid confusion, load them explicitly from |
+// libSystem.dylib. |
+class DnsInfoApi { |
+ public: |
+ typedef const char* (*dns_configuration_notify_key_t)(); |
+ typedef dns_config_t* (*dns_configuration_copy_t)(); |
+ typedef void (*dns_configuration_free_t)(dns_config_t*); |
+ |
+ DnsInfoApi() |
+ : dns_configuration_notify_key(NULL), |
+ dns_configuration_copy(NULL), |
+ dns_configuration_free(NULL) { |
+ handle_ = dlopen("/usr/lib/libSystem.dylib", |
+ RTLD_LAZY | RTLD_NOLOAD); |
+ if (!handle_) |
+ return; |
+ dns_configuration_notify_key = |
+ reinterpret_cast<dns_configuration_notify_key_t>( |
+ dlsym(handle_, "dns_configuration_notify_key")); |
+ dns_configuration_copy = |
+ reinterpret_cast<dns_configuration_copy_t>( |
+ dlsym(handle_, "dns_configuration_copy")); |
+ dns_configuration_free = |
+ reinterpret_cast<dns_configuration_free_t>( |
+ dlsym(handle_, "dns_configuration_free")); |
+ } |
+ |
+ ~DnsInfoApi() { |
+ if (handle_) |
+ dlclose(handle_); |
+ } |
+ |
+ dns_configuration_notify_key_t dns_configuration_notify_key; |
+ dns_configuration_copy_t dns_configuration_copy; |
+ dns_configuration_free_t dns_configuration_free; |
+ |
+ private: |
+ void* handle_; |
+}; |
+ |
+const DnsInfoApi& GetDnsInfoApi() { |
+ static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER; |
+ return api.Get(); |
+} |
+ |
+struct DnsConfigTDeleter { |
+ inline void operator()(dns_config_t* ptr) const { |
+ if (GetDnsInfoApi().dns_configuration_free) |
+ GetDnsInfoApi().dns_configuration_free(ptr); |
+ } |
+}; |
+ |
+} // namespace |
+ |
+namespace net { |
+namespace internal { |
+ |
+bool DnsConfigWatcher::Watch( |
+ const base::Callback<void(bool succeeded)>& callback) { |
+ if (!GetDnsInfoApi().dns_configuration_notify_key) |
+ return false; |
+ return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(), |
+ callback); |
+} |
+ |
+// static |
+ConfigParsePosixResult DnsConfigWatcher::CheckDnsConfig() { |
+ if (!GetDnsInfoApi().dns_configuration_copy) |
+ return CONFIG_PARSE_POSIX_NO_DNSINFO; |
+ scoped_ptr<dns_config_t, DnsConfigTDeleter> dns_config( |
+ GetDnsInfoApi().dns_configuration_copy()); |
+ if (!dns_config) |
+ return CONFIG_PARSE_POSIX_NO_DNSINFO; |
+ |
+ // TODO(szym): Parse dns_config_t for resolvers rather than res_state. |
+ // DnsClient can't handle domain-specific unscoped resolvers. |
+ unsigned num_resolvers = 0; |
+ for (int i = 0; i < dns_config->n_resolver; ++i) { |
+ dns_resolver_t* resolver = dns_config->resolver[i]; |
+ if (!resolver->n_nameserver) |
+ continue; |
+ if (resolver->options && !strcmp(resolver->options, "mdns")) |
+ continue; |
+ ++num_resolvers; |
+ } |
+ if (num_resolvers > 1) |
+ return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS; |
+ return CONFIG_PARSE_POSIX_OK; |
+} |
+ |
+} // naespace internal |
+} // namespace net |