| // 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 "starboard/types.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; |
| std::unique_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; |
| } |
| |
| } // namespace internal |
| } // namespace net |