diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index dacd55fc83c1..4dcdb3ac79a1 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -10,13 +10,13 @@ # include # include # include +# define RES_RETRY_ON_FAILURE #endif #include #include #include "nsHostResolver.h" #include "nsError.h" -#include "nsIOService.h" #include "nsISupports.h" #include "nsISupportsUtils.h" #include "nsIThreadManager.h" @@ -98,54 +98,45 @@ LazyLogModule gHostResolverLog("nsHostResolver"); //---------------------------------------------------------------------------- -#if defined(HAVE_RES_NINIT) +#if defined(RES_RETRY_ON_FAILURE) -// The nsResState class manages the res state. -// This class ensures the resolver state is reset based on network change events -// to maintain correct DNS resolutions. -class MOZ_STACK_CLASS nsResState { +// this class represents the resolver state for a given thread. if we +// encounter a lookup failure, then we can invoke the Reset method on an +// instance of this class to reset the resolver (in case /etc/resolv.conf +// for example changed). this is mainly an issue on GNU systems since glibc +// only reads in /etc/resolv.conf once per thread. it may be an issue on +// other systems as well. + +class nsResState { public: - // Set mLastReset to now, which should be larger than last network change - // time, so we won't reset when the thread just started. - nsResState() : mLastReset(PR_IntervalNow()) {} + nsResState() + // initialize mLastReset to the time when this object + // is created. this means that a reset will not occur + // if a thread is too young. the alternative would be + // to initialize this to the beginning of time, so that + // the first failure would cause a reset, but since the + // thread would have just started up, it likely would + // already have current /etc/resolv.conf info. + : mLastReset(PR_IntervalNow()) {} - ~nsResState() { - if (_res.options & RES_INIT) { - res_nclose(&_res); - } - } - - void Init() { - if (!(_res.options & RES_INIT)) { - auto result = res_ninit(&_res); - LOG(("nsResState > 'res_ninit' returned %d ", result)); - } - } - - void MaybeReset() { - if (mLastReset > gIOService->LastNetworkLinkChange()) { - return; - } - - PRIntervalTime now = PR_IntervalNow(); + bool Reset() { // reset no more than once per second - if (PR_IntervalToSeconds(now - mLastReset) < 1) { - return; + if (PR_IntervalToSeconds(PR_IntervalNow() - mLastReset) < 1) { + return false; } - if (_res.options & RES_INIT) { - res_nclose(&_res); - } + mLastReset = PR_IntervalNow(); + auto result = res_ninit(&_res); - mLastReset = now; - Init(); + LOG(("nsResState::Reset() > 'res_ninit' returned %d", result)); + return (result == 0); } private: PRIntervalTime mLastReset; }; -#endif // HAVE_RES_NINIT +#endif // RES_RETRY_ON_FAILURE class DnsThreadListener final : public nsIThreadPoolListener { NS_DECL_THREADSAFE_ISUPPORTS @@ -233,6 +224,19 @@ nsresult nsHostResolver::Init() MOZ_NO_THREAD_SAFETY_ANALYSIS { "Could not register DNS pref callback."); } +#if defined(HAVE_RES_NINIT) + // We want to make sure the system is using the correct resolver settings, + // so we force it to reload those settings whenever we startup a subsequent + // nsHostResolver instance. We assume that there is no reason to do this + // for the first nsHostResolver instance since that is usually created + // during application startup. + static int initCount = 0; + if (initCount++ > 0) { + auto result = res_ninit(&_res); + LOG(("nsHostResolver::Init > 'res_ninit' returned %d", result)); + } +#endif + // We can configure the threadpool to keep threads alive for a while after // the last ThreadFunc task has been executed. int32_t poolTimeoutSecs = Preferences::GetInt(kPrefThreadIdleTime, 60); @@ -1841,9 +1845,8 @@ size_t nsHostResolver::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { void nsHostResolver::ThreadFunc() { LOG(("DNS lookup thread - starting execution.\n")); -#if defined(HAVE_RES_NINIT) +#if defined(RES_RETRY_ON_FAILURE) nsResState rs; - rs.Init(); #endif RefPtr rec; RefPtr ai; @@ -1884,11 +1887,14 @@ void nsHostResolver::ThreadFunc() { continue; } -#if defined(HAVE_RES_NINIT) - rs.MaybeReset(); -#endif nsresult status = GetAddrInfo(rec->host, rec->af, rec->flags, getter_AddRefs(ai), getTtl); +#if defined(RES_RETRY_ON_FAILURE) + if (NS_FAILED(status) && rs.Reset()) { + status = GetAddrInfo(rec->host, rec->af, rec->flags, getter_AddRefs(ai), + getTtl); + } +#endif mozilla::glean::networking::dns_native_count .EnumGet(rec->pb ? glean::networking::DnsNativeCountLabel::ePrivate