diff options
Diffstat (limited to 'net/base')
-rw-r--r-- | net/base/dns_reload_timer.cc | 91 | ||||
-rw-r--r-- | net/base/dns_reload_timer.h | 22 | ||||
-rw-r--r-- | net/base/host_resolver_proc.cc | 83 |
3 files changed, 115 insertions, 81 deletions
diff --git a/net/base/dns_reload_timer.cc b/net/base/dns_reload_timer.cc new file mode 100644 index 0000000..5931c5b --- /dev/null +++ b/net/base/dns_reload_timer.cc @@ -0,0 +1,91 @@ +// Copyright (c) 2010 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/base/dns_reload_timer.h" + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) +#include "base/singleton.h" +#include "base/thread_local_storage.h" +#include "base/time.h" + +namespace net { + +// On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting +// in DNS queries failing either because nameservers are unknown on startup +// or because nameserver info has changed as a result of e.g. connecting to +// a new network. Some distributions patch glibc to stat /etc/resolv.conf +// to try to automatically detect such changes but these patches are not +// universal and even patched systems such as Jaunty appear to need calls +// to res_ninit to reload the nameserver information in different threads. +// +// We adopt the Mozilla solution here which is to call res_ninit when +// lookups fail and to rate limit the reloading to once per second per +// thread. +// +// OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do +// the same trick there. + +// Keep a timer per calling thread to rate limit the calling of res_ninit. +class DnsReloadTimer { + public: + // Check if the timer for the calling thread has expired. When no + // timer exists for the calling thread, create one. + bool Expired() { + const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1); + base::TimeTicks now = base::TimeTicks::Now(); + base::TimeTicks* timer_ptr = + static_cast<base::TimeTicks*>(tls_index_.Get()); + + if (!timer_ptr) { + timer_ptr = new base::TimeTicks(); + *timer_ptr = base::TimeTicks::Now(); + tls_index_.Set(timer_ptr); + // Return true to reload dns info on the first call for each thread. + return true; + } else if (now - *timer_ptr > kRetryTime) { + *timer_ptr = now; + return true; + } else { + return false; + } + } + + // Free the allocated timer. + static void SlotReturnFunction(void* data) { + base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data); + delete tls_data; + } + + private: + friend struct DefaultSingletonTraits<DnsReloadTimer>; + + DnsReloadTimer() { + // During testing the DnsReloadTimer Singleton may be created and destroyed + // multiple times. Initialize the ThreadLocalStorage slot only once. + if (!tls_index_.initialized()) + tls_index_.Initialize(SlotReturnFunction); + } + + ~DnsReloadTimer() { + } + + // We use thread local storage to identify which base::TimeTicks to + // interact with. + static ThreadLocalStorage::Slot tls_index_ ; + + DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); +}; + +// A TLS slot to the TimeTicks for the current thread. +// static +ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); + +bool DnsReloadTimerHasExpired() { + DnsReloadTimer* dns_timer = Singleton<DnsReloadTimer>::get(); + return dns_timer->Expired(); +} + +} // namespace net + +#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) diff --git a/net/base/dns_reload_timer.h b/net/base/dns_reload_timer.h new file mode 100644 index 0000000..fdd90a7 --- /dev/null +++ b/net/base/dns_reload_timer.h @@ -0,0 +1,22 @@ +// Copyright (c) 2009 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. + +#ifndef NET_BASE_DNS_RELOAD_TIMER_H_ +#define NET_BASE_DNS_RELOAD_TIMER_H_ +#pragma once + +#include "build/build_config.h" + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) +namespace net { + +// DnsReloadTimerExpired tests the thread local DNS reload timer and, if it has +// expired, returns true and resets the timer. See comments in +// host_resolver_proc.cc for details. +bool DnsReloadTimerHasExpired(); + +} // namespace net +#endif + +#endif // NET_BASE_DNS_RELOAD_TIMER_H_ diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc index 8e8034f..39d4fc4 100644 --- a/net/base/host_resolver_proc.cc +++ b/net/base/host_resolver_proc.cc @@ -11,16 +11,11 @@ #endif #include "base/logging.h" -#include "base/time.h" #include "net/base/address_list.h" +#include "net/base/dns_reload_timer.h" #include "net/base/net_errors.h" #include "net/base/sys_addrinfo.h" -#if defined(OS_POSIX) && !defined(OS_MACOSX) -#include "base/singleton.h" -#include "base/thread_local_storage.h" -#endif - namespace net { HostResolverProc* HostResolverProc::default_proc_ = NULL; @@ -83,79 +78,6 @@ int HostResolverProc::ResolveUsingPrevious( addrlist, os_error); } -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) -// On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting -// in DNS queries failing either because nameservers are unknown on startup -// or because nameserver info has changed as a result of e.g. connecting to -// a new network. Some distributions patch glibc to stat /etc/resolv.conf -// to try to automatically detect such changes but these patches are not -// universal and even patched systems such as Jaunty appear to need calls -// to res_ninit to reload the nameserver information in different threads. -// -// We adopt the Mozilla solution here which is to call res_ninit when -// lookups fail and to rate limit the reloading to once per second per -// thread. -// -// OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do -// the same trick there. - -// Keep a timer per calling thread to rate limit the calling of res_ninit. -class DnsReloadTimer { - public: - // Check if the timer for the calling thread has expired. When no - // timer exists for the calling thread, create one. - bool Expired() { - const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1); - base::TimeTicks now = base::TimeTicks::Now(); - base::TimeTicks* timer_ptr = - static_cast<base::TimeTicks*>(tls_index_.Get()); - - if (!timer_ptr) { - timer_ptr = new base::TimeTicks(); - *timer_ptr = base::TimeTicks::Now(); - tls_index_.Set(timer_ptr); - // Return true to reload dns info on the first call for each thread. - return true; - } else if (now - *timer_ptr > kRetryTime) { - *timer_ptr = now; - return true; - } else { - return false; - } - } - - // Free the allocated timer. - static void SlotReturnFunction(void* data) { - base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data); - delete tls_data; - } - - private: - friend struct DefaultSingletonTraits<DnsReloadTimer>; - - DnsReloadTimer() { - // During testing the DnsReloadTimer Singleton may be created and destroyed - // multiple times. Initialize the ThreadLocalStorage slot only once. - if (!tls_index_.initialized()) - tls_index_.Initialize(SlotReturnFunction); - } - - ~DnsReloadTimer() { - } - - // We use thread local storage to identify which base::TimeTicks to - // interact with. - static ThreadLocalStorage::Slot tls_index_ ; - - DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer); -}; - -// A TLS slot to the TimeTicks for the current thread. -// static -ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED); - -#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) - int SystemHostResolverProc(const std::string& host, AddressFamily address_family, HostResolverFlags host_resolver_flags, @@ -230,10 +152,9 @@ int SystemHostResolverProc(const std::string& host, int err = getaddrinfo(host.c_str(), NULL, &hints, &ai); #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) - net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get(); // If we fail, re-initialise the resolver just in case there have been any // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info. - if (err && dns_timer->Expired()) { + if (err && DnsReloadTimerHasExpired()) { res_nclose(&_res); if (!res_ninit(&_res)) err = getaddrinfo(host.c_str(), NULL, &hints, &ai); |