зеркало из https://github.com/mozilla/pjs.git
329 строки
13 KiB
C++
329 строки
13 KiB
C++
/* vim:set ts=4 sw=4 sts=4 et cin: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla.
|
|
*
|
|
* The Initial Developer of the Original Code is IBM Corporation.
|
|
* Portions created by IBM Corporation are Copyright (C) 2003
|
|
* IBM Corporation. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* IBM Corp.
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#ifndef nsHostResolver_h__
|
|
#define nsHostResolver_h__
|
|
|
|
#include "nscore.h"
|
|
#include "nsAtomicRefcnt.h"
|
|
#include "prclist.h"
|
|
#include "prnetdb.h"
|
|
#include "pldhash.h"
|
|
#include "mozilla/CondVar.h"
|
|
#include "mozilla/Mutex.h"
|
|
#include "nsISupportsImpl.h"
|
|
#include "nsIDNSListener.h"
|
|
#include "nsString.h"
|
|
#include "nsTArray.h"
|
|
|
|
class nsHostResolver;
|
|
class nsHostRecord;
|
|
class nsResolveHostCallback;
|
|
|
|
/* XXX move this someplace more generic */
|
|
#define NS_DECL_REFCOUNTED_THREADSAFE(classname) \
|
|
private: \
|
|
nsAutoRefCnt _refc; \
|
|
public: \
|
|
PRInt32 AddRef() { \
|
|
PRInt32 n = NS_AtomicIncrementRefcnt(_refc); \
|
|
NS_LOG_ADDREF(this, n, #classname, sizeof(classname)); \
|
|
return n; \
|
|
} \
|
|
PRInt32 Release() { \
|
|
PRInt32 n = NS_AtomicDecrementRefcnt(_refc); \
|
|
NS_LOG_RELEASE(this, n, #classname); \
|
|
if (n == 0) \
|
|
delete this; \
|
|
return n; \
|
|
}
|
|
|
|
#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;
|
|
PRUint16 flags;
|
|
PRUint16 af;
|
|
};
|
|
|
|
/**
|
|
* nsHostRecord - ref counted object type stored in host resolver cache.
|
|
*/
|
|
class nsHostRecord : public PRCList, public nsHostKey
|
|
{
|
|
typedef mozilla::Mutex Mutex;
|
|
|
|
public:
|
|
NS_DECL_REFCOUNTED_THREADSAFE(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| */
|
|
PRAddrInfo *addr_info;
|
|
PRNetAddr *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. */
|
|
|
|
PRUint32 expiration; /* measured in minutes since epoch */
|
|
|
|
bool HasResult() const { return addr_info || addr || negative; }
|
|
|
|
// hold addr_info_lock when calling the blacklist functions
|
|
bool Blacklisted(PRNetAddr *query);
|
|
void ResetBlacklist();
|
|
void ReportUnusable(PRNetAddr *addr);
|
|
|
|
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 */
|
|
|
|
// 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;
|
|
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* nsHostResolver - an asynchronous host name resolver.
|
|
*/
|
|
class nsHostResolver
|
|
{
|
|
typedef mozilla::CondVar CondVar;
|
|
typedef mozilla::Mutex Mutex;
|
|
|
|
public:
|
|
/**
|
|
* host resolver instances are reference counted.
|
|
*/
|
|
NS_DECL_REFCOUNTED_THREADSAFE(nsHostResolver)
|
|
|
|
/**
|
|
* creates an addref'd instance of a nsHostResolver object.
|
|
*/
|
|
static nsresult Create(PRUint32 maxCacheEntries, // zero disables cache
|
|
PRUint32 maxCacheLifetime, // minutes
|
|
PRUint32 lifetimeGracePeriod, // minutes
|
|
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,
|
|
PRUint16 flags,
|
|
PRUint16 af,
|
|
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,
|
|
PRUint16 flags,
|
|
PRUint16 af,
|
|
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,
|
|
PRUint16 flags,
|
|
PRUint16 af,
|
|
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 = 1 << 0,
|
|
RES_CANON_NAME = 1 << 1,
|
|
RES_PRIORITY_MEDIUM = 1 << 2,
|
|
RES_PRIORITY_LOW = 1 << 3,
|
|
RES_SPECULATE = 1 << 4
|
|
};
|
|
|
|
private:
|
|
nsHostResolver(PRUint32 maxCacheEntries = 50, PRUint32 maxCacheLifetime = 1,
|
|
PRUint32 lifetimeGracePeriod = 0);
|
|
~nsHostResolver();
|
|
|
|
nsresult Init();
|
|
nsresult IssueLookup(nsHostRecord *);
|
|
bool GetHostToLookup(nsHostRecord **m);
|
|
void OnLookupComplete(nsHostRecord *, nsresult, PRAddrInfo *);
|
|
void DeQueue(PRCList &aQ, nsHostRecord **aResult);
|
|
void ClearPendingQueue(PRCList *aPendingQueue);
|
|
nsresult ConditionallyCreateThread(nsHostRecord *rec);
|
|
|
|
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
|
|
};
|
|
|
|
PRUint32 mMaxCacheEntries;
|
|
PRUint32 mMaxCacheLifetime;
|
|
PRUint32 mGracePeriod;
|
|
Mutex mLock;
|
|
CondVar mIdleThreadCV;
|
|
PRUint32 mNumIdleThreads;
|
|
PRUint32 mThreadCount;
|
|
PRUint32 mActiveAnyThreadCount;
|
|
PLDHashTable mDB;
|
|
PRCList mHighQ;
|
|
PRCList mMediumQ;
|
|
PRCList mLowQ;
|
|
PRCList mEvictionQ;
|
|
PRUint32 mEvictionQSize;
|
|
PRUint32 mPendingCount;
|
|
PRTime mCreationTime;
|
|
bool mShutdown;
|
|
PRIntervalTime mLongIdleTimeout;
|
|
PRIntervalTime mShortIdleTimeout;
|
|
};
|
|
|
|
#endif // nsHostResolver_h__
|