mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
373 lines
14 KiB
C++
373 lines
14 KiB
C++
/* 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__
|