| // 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; | 
 | } | 
 |  | 
 | }  // namespace internal | 
 | }  // namespace net |