15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/dns_reloader.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \ 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !defined(OS_ANDROID) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <resolv.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_local_storage.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/network_change_notifier.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in DNS queries failing either because nameservers are unknown on startup 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or because nameserver info has changed as a result of e.g. connecting to 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a new network. Some distributions patch glibc to stat /etc/resolv.conf 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to try to automatically detect such changes but these patches are not 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// universal and even patched systems such as Jaunty appear to need calls 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to res_ninit to reload the nameserver information in different threads. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// To fix this, on systems with FilePathWatcher support, we use 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NetworkChangeNotifier::DNSObserver to monitor /etc/resolv.conf to 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// enable us to respond to DNS changes and reload the resolver state. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the same trick there and most *BSD's don't yet have support for 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FilePathWatcher (but perhaps the new kqueue mac code just needs to be 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ported to *BSD to support that). 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Android does not have /etc/resolv.conf. The system takes care of nameserver 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// changes, so none of this is needed. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DnsReloader : public net::NetworkChangeNotifier::DNSObserver { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct ReloadState { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int resolver_generation; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NetworkChangeNotifier::DNSObserver: 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnDNSChanged() OVERRIDE { 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(base::MessageLoopForIO::IsCurrent()); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock l(lock_); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resolver_generation_++; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MaybeReload() { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReloadState* reload_state = static_cast<ReloadState*>(tls_index_.Get()); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AutoLock l(lock_); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!reload_state) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reload_state = new ReloadState(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reload_state->resolver_generation = resolver_generation_; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res_ninit(&_res); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Set(reload_state); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (reload_state->resolver_generation != resolver_generation_) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reload_state->resolver_generation = resolver_generation_; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is safe to call res_nclose here since we know res_ninit will have 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // been called above. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res_nclose(&_res); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res_ninit(&_res); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Free the allocated state. 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void SlotReturnFunction(void* data) { 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReloadState* reload_state = static_cast<ReloadState*>(data); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reload_state) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res_nclose(&_res); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete reload_state; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DnsReloader() : resolver_generation_(0) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tls_index_.Initialize(SlotReturnFunction); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::NetworkChangeNotifier::AddDNSObserver(this); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~DnsReloader() { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); // LeakyLazyInstance is not destructed. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Lock lock_; // Protects resolver_generation_. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int resolver_generation_; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend struct base::DefaultLazyInstanceTraits<DnsReloader>; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use thread local storage to identify which ReloadState to interact with. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static base::ThreadLocalStorage::StaticSlot tls_index_; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DnsReloader); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A TLS slot to the ReloadState for the current thread. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::ThreadLocalStorage::StaticSlot DnsReloader::tls_index_ = TLS_INITIALIZER; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::LazyInstance<DnsReloader>::Leaky 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_dns_reloader = LAZY_INSTANCE_INITIALIZER; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EnsureDnsReloaderInit() { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DnsReloader* t ALLOW_UNUSED = g_dns_reloader.Pointer(); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsReloaderMaybeReload() { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This routine can be called by any of the DNS worker threads. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DnsReloader* dns_reloader = g_dns_reloader.Pointer(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dns_reloader->MaybeReload(); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // !defined(OS_ANDROID) 126