diff options
Diffstat (limited to 'netwerk/dns/nsHostResolver.h')
-rw-r--r-- | netwerk/dns/nsHostResolver.h | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h new file mode 100644 index 000000000..4c37ff0d3 --- /dev/null +++ b/netwerk/dns/nsHostResolver.h @@ -0,0 +1,372 @@ +/* vim:set ts=4 sw=4 sts=4 et cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsHostResolver_h__ +#define nsHostResolver_h__ + +#include "nscore.h" +#include "prclist.h" +#include "prnetdb.h" +#include "PLDHashTable.h" +#include "mozilla/CondVar.h" +#include "mozilla/Mutex.h" +#include "nsISupportsImpl.h" +#include "nsIDNSListener.h" +#include "nsIDNSService.h" +#include "nsString.h" +#include "nsTArray.h" +#include "GetAddrInfo.h" +#include "mozilla/net/DNS.h" +#include "mozilla/net/DashboardTypes.h" +#include "mozilla/TimeStamp.h" + +class nsHostResolver; +class nsHostRecord; +class nsResolveHostCallback; + +#define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3 +#define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5 +#define MAX_NON_PRIORITY_REQUESTS 150 + +#define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \ + MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY) + +struct nsHostKey +{ + const char *host; + uint16_t flags; + uint16_t af; + const char *netInterface; +}; + +/** + * nsHostRecord - ref counted object type stored in host resolver cache. + */ +class nsHostRecord : public PRCList, public nsHostKey +{ + typedef mozilla::Mutex Mutex; + +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostRecord) + + /* instantiates a new host record */ + static nsresult Create(const nsHostKey *key, nsHostRecord **record); + + /* a fully resolved host record has either a non-null |addr_info| or |addr| + * field. if |addr_info| is null, it implies that the |host| is an IP + * address literal. in which case, |addr| contains the parsed address. + * otherwise, if |addr_info| is non-null, then it contains one or many + * IP addresses corresponding to the given host name. if both |addr_info| + * and |addr| are null, then the given host has not yet been fully resolved. + * |af| is the address family of the record we are querying for. + */ + + /* the lock protects |addr_info| and |addr_info_gencnt| because they + * are mutable and accessed by the resolver worker thread and the + * nsDNSService2 class. |addr| doesn't change after it has been + * assigned a value. only the resolver worker thread modifies + * nsHostRecord (and only in nsHostResolver::OnLookupComplete); + * the other threads just read it. therefore the resolver worker + * thread doesn't need to lock when reading |addr_info|. + */ + Mutex addr_info_lock; + int addr_info_gencnt; /* generation count of |addr_info| */ + mozilla::net::AddrInfo *addr_info; + mozilla::net::NetAddr *addr; + bool negative; /* True if this record is a cache of a failed lookup. + Negative cache entries are valid just like any other + (though never for more than 60 seconds), but a use + of that negative entry forces an asynchronous refresh. */ + + enum ExpirationStatus { + EXP_VALID, + EXP_GRACE, + EXP_EXPIRED, + }; + + ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const; + + // When the record began being valid. Used mainly for bookkeeping. + mozilla::TimeStamp mValidStart; + + // When the record is no longer valid (it's time of expiration) + mozilla::TimeStamp mValidEnd; + + // When the record enters its grace period. This must be before mValidEnd. + // If a record is in its grace period (and not expired), it will be used + // but a request to refresh it will be made. + mozilla::TimeStamp mGraceStart; + + // Convenience function for setting the timestamps above (mValidStart, + // mValidEnd, and mGraceStart). valid and grace are durations in seconds. + void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, + unsigned int grace); + void CopyExpirationTimesAndFlagsFrom(const nsHostRecord *aFromHostRecord); + + // Checks if the record is usable (not expired and has a value) + bool HasUsableResult(const mozilla::TimeStamp& now, uint16_t queryFlags = 0) const; + + // hold addr_info_lock when calling the blacklist functions + bool Blacklisted(mozilla::net::NetAddr *query); + void ResetBlacklist(); + void ReportUnusable(mozilla::net::NetAddr *addr); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + enum DnsPriority { + DNS_PRIORITY_LOW, + DNS_PRIORITY_MEDIUM, + DNS_PRIORITY_HIGH, + }; + static DnsPriority GetPriority(uint16_t aFlags); + + bool RemoveOrRefresh(); // Mark records currently being resolved as needed + // to resolve again. + +private: + friend class nsHostResolver; + + + PRCList callbacks; /* list of callbacks */ + + bool resolving; /* true if this record is being resolved, which means + * that it is either on the pending queue or owned by + * one of the worker threads. */ + + bool onQueue; /* true if pending and on the queue (not yet given to getaddrinfo())*/ + bool usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */ + bool mDoomed; /* explicitly expired */ + +#if TTL_AVAILABLE + bool mGetTtl; +#endif + + // The number of times ReportUnusable() has been called in the record's + // lifetime. + uint32_t mBlacklistedCount; + + // when the results from this resolve is returned, it is not to be + // trusted, but instead a new resolve must be made! + bool mResolveAgain; + + // a list of addresses associated with this record that have been reported + // as unusable. the list is kept as a set of strings to make it independent + // of gencnt. + nsTArray<nsCString> mBlacklistedItems; + + explicit nsHostRecord(const nsHostKey *key); /* use Create() instead */ + ~nsHostRecord(); +}; + +/** + * ResolveHost callback object. It's PRCList members are used by + * the nsHostResolver and should not be used by anything else. + */ +class NS_NO_VTABLE nsResolveHostCallback : public PRCList +{ +public: + /** + * OnLookupComplete + * + * this function is called to complete a host lookup initiated by + * nsHostResolver::ResolveHost. it may be invoked recursively from + * ResolveHost or on an unspecified background thread. + * + * NOTE: it is the responsibility of the implementor of this method + * to handle the callback in a thread safe manner. + * + * @param resolver + * nsHostResolver object associated with this result + * @param record + * the host record containing the results of the lookup + * @param status + * if successful, |record| contains non-null results + */ + virtual void OnLookupComplete(nsHostResolver *resolver, + nsHostRecord *record, + nsresult status) = 0; + /** + * EqualsAsyncListener + * + * Determines if the listener argument matches the listener member var. + * For subclasses not implementing a member listener, should return false. + * For subclasses having a member listener, the function should check if + * they are the same. Used for cases where a pointer to an object + * implementing nsResolveHostCallback is unknown, but a pointer to + * the original listener is known. + * + * @param aListener + * nsIDNSListener object associated with the original request + */ + virtual bool EqualsAsyncListener(nsIDNSListener *aListener) = 0; + + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0; +}; + +/** + * nsHostResolver - an asynchronous host name resolver. + */ +class nsHostResolver +{ + typedef mozilla::CondVar CondVar; + typedef mozilla::Mutex Mutex; + +public: + /** + * host resolver instances are reference counted. + */ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostResolver) + + /** + * creates an addref'd instance of a nsHostResolver object. + */ + static nsresult Create(uint32_t maxCacheEntries, // zero disables cache + uint32_t defaultCacheEntryLifetime, // seconds + uint32_t defaultGracePeriod, // seconds + nsHostResolver **resolver); + + /** + * puts the resolver in the shutdown state, which will cause any pending + * callbacks to be detached. any future calls to ResolveHost will fail. + */ + void Shutdown(); + + /** + * resolve the given hostname asynchronously. the caller can synthesize + * a synchronous host lookup using a lock and a cvar. as noted above + * the callback will occur re-entrantly from an unspecified thread. the + * host lookup cannot be canceled (cancelation can be layered above this + * by having the callback implementation return without doing anything). + */ + nsresult ResolveHost(const char *hostname, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsResolveHostCallback *callback); + + /** + * removes the specified callback from the nsHostRecord for the given + * hostname, flags, and address family. these parameters should correspond + * to the parameters passed to ResolveHost. this function executes the + * callback if the callback is still pending with the given status. + */ + void DetachCallback(const char *hostname, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsResolveHostCallback *callback, + nsresult status); + + /** + * Cancels an async request associated with the hostname, flags, + * address family and listener. Cancels first callback found which matches + * these criteria. These parameters should correspond to the parameters + * passed to ResolveHost. If this is the last callback associated with the + * host record, it is removed from any request queues it might be on. + */ + void CancelAsyncRequest(const char *host, + uint16_t flags, + uint16_t af, + const char *netInterface, + nsIDNSListener *aListener, + nsresult status); + /** + * values for the flags parameter passed to ResolveHost and DetachCallback + * that may be bitwise OR'd together. + * + * NOTE: in this implementation, these flags correspond exactly in value + * to the flags defined on nsIDNSService. + */ + enum { + RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE, + RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME, + RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM, + RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW, + RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE, + //RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used + RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE, + //RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used + RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION + }; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; + + /** + * Flush the DNS cache. + */ + void FlushCache(); + +private: + explicit nsHostResolver(uint32_t maxCacheEntries, + uint32_t defaultCacheEntryLifetime, + uint32_t defaultGracePeriod); + ~nsHostResolver(); + + nsresult Init(); + nsresult IssueLookup(nsHostRecord *); + bool GetHostToLookup(nsHostRecord **m); + + enum LookupStatus { + LOOKUP_OK, + LOOKUP_RESOLVEAGAIN, + }; + + LookupStatus OnLookupComplete(nsHostRecord *, nsresult, mozilla::net::AddrInfo *); + void DeQueue(PRCList &aQ, nsHostRecord **aResult); + void ClearPendingQueue(PRCList *aPendingQueue); + nsresult ConditionallyCreateThread(nsHostRecord *rec); + + /** + * Starts a new lookup in the background for entries that are in the grace + * period with a failed connect or all cached entries are negative. + */ + nsresult ConditionallyRefreshRecord(nsHostRecord *rec, const char *host); + + static void MoveQueue(nsHostRecord *aRec, PRCList &aDestQ); + + static void ThreadFunc(void *); + + enum { + METHOD_HIT = 1, + METHOD_RENEWAL = 2, + METHOD_NEGATIVE_HIT = 3, + METHOD_LITERAL = 4, + METHOD_OVERFLOW = 5, + METHOD_NETWORK_FIRST = 6, + METHOD_NETWORK_SHARED = 7 + }; + + uint32_t mMaxCacheEntries; + uint32_t mDefaultCacheLifetime; // granularity seconds + uint32_t mDefaultGracePeriod; // granularity seconds + mutable Mutex mLock; // mutable so SizeOfIncludingThis can be const + CondVar mIdleThreadCV; + PLDHashTable mDB; + PRCList mHighQ; + PRCList mMediumQ; + PRCList mLowQ; + PRCList mEvictionQ; + uint32_t mEvictionQSize; + PRTime mCreationTime; + PRIntervalTime mLongIdleTimeout; + PRIntervalTime mShortIdleTimeout; + + mozilla::Atomic<bool> mShutdown; + mozilla::Atomic<uint32_t> mNumIdleThreads; + mozilla::Atomic<uint32_t> mThreadCount; + mozilla::Atomic<uint32_t> mActiveAnyThreadCount; + mozilla::Atomic<uint32_t> mPendingCount; + + // Set the expiration time stamps appropriately. + void PrepareRecordExpiration(nsHostRecord* rec) const; + +public: + /* + * Called by the networking dashboard via the DnsService2 + */ + void GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *); +}; + +#endif // nsHostResolver_h__ |