зеркало из https://github.com/mozilla/pjs.git
fixes bug 219376 "Trying to resolve IP's via DNS (Failed connections stall instead of giving Connection Failure Error; pages stop/don't finish/complete loading if ad hosts/scripts fail)" r=dougt sr=bienvenu,bryner
This commit is contained in:
Родитель
2547c1c88c
Коммит
93657ac421
|
@ -661,6 +661,7 @@ nsSocketTransport::nsSocketTransport()
|
|||
, mAttached(PR_FALSE)
|
||||
, mInputClosed(PR_TRUE)
|
||||
, mOutputClosed(PR_TRUE)
|
||||
, mResolving(PR_FALSE)
|
||||
, mLock(PR_NewLock())
|
||||
, mFD(nsnull)
|
||||
, mFDref(0)
|
||||
|
@ -802,26 +803,21 @@ nsSocketTransport::ResolveHost()
|
|||
LOG(("nsSocketTransport::ResolveHost [this=%x]\n", this));
|
||||
|
||||
nsresult rv;
|
||||
// if this is a numeric ip address, then we can simply circumvent the
|
||||
// DNS resolver.
|
||||
if (PR_StringToNetAddr(SocketHost().get(), &mNetAddr) == PR_SUCCESS) {
|
||||
mNetAddr.inet.port = PR_htons(SocketPort());
|
||||
mState = STATE_RESOLVING;
|
||||
// not sending a DNS record...
|
||||
rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, NS_OK, nsnull);
|
||||
}
|
||||
else {
|
||||
|
||||
nsCOMPtr<nsIDNSService> dns = do_GetService(kDNSServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mResolving = PR_TRUE;
|
||||
|
||||
rv = dns->AsyncResolve(SocketHost(), PR_FALSE, this, nsnull,
|
||||
getter_AddRefs(mDNSRequest));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG((" advancing to STATE_RESOLVING\n"));
|
||||
mState = STATE_RESOLVING;
|
||||
// only report that we are resolving if we are still resolving...
|
||||
if (mResolving)
|
||||
SendStatus(STATUS_RESOLVING);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1631,6 +1627,9 @@ nsSocketTransport::OnLookupComplete(nsIDNSRequest *request,
|
|||
nsIDNSRecord *rec,
|
||||
nsresult status)
|
||||
{
|
||||
// flag host lookup complete for the benefit of the ResolveHost method.
|
||||
mResolving = PR_FALSE;
|
||||
|
||||
nsresult rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, status, rec);
|
||||
|
||||
// if posting a message fails, then we should assume that the socket
|
||||
|
|
|
@ -196,6 +196,10 @@ private:
|
|||
PRPackedBool mInputClosed;
|
||||
PRPackedBool mOutputClosed;
|
||||
|
||||
// this flag is used to determine if the results of a host lookup arrive
|
||||
// recursively or not. this flag is not protected by any lock.
|
||||
PRPackedBool mResolving;
|
||||
|
||||
nsCOMPtr<nsIDNSRequest> mDNSRequest;
|
||||
nsCOMPtr<nsIDNSRecord> mDNSRecord;
|
||||
PRNetAddr mNetAddr;
|
||||
|
|
|
@ -63,15 +63,15 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDNSRECORD
|
||||
|
||||
nsDNSRecord(nsAddrInfo *ai)
|
||||
: mAddrInfo(ai)
|
||||
nsDNSRecord(nsHostRecord *hostRecord)
|
||||
: mHostRecord(hostRecord)
|
||||
, mIter(nsnull)
|
||||
, mDone(PR_FALSE) {}
|
||||
|
||||
private:
|
||||
virtual ~nsDNSRecord() {}
|
||||
|
||||
nsRefPtr<nsAddrInfo> mAddrInfo;
|
||||
nsRefPtr<nsHostRecord> mHostRecord;
|
||||
void *mIter;
|
||||
PRBool mDone;
|
||||
};
|
||||
|
@ -81,23 +81,43 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsDNSRecord, nsIDNSRecord)
|
|||
NS_IMETHODIMP
|
||||
nsDNSRecord::GetCanonicalName(nsACString &result)
|
||||
{
|
||||
NS_ENSURE_TRUE(mAddrInfo, NS_ERROR_NOT_AVAILABLE);
|
||||
result.Assign(PR_GetCanonNameFromAddrInfo(mAddrInfo->get()));
|
||||
// if the record is for an IP address literal, then the canonical
|
||||
// host name is the IP address literal.
|
||||
const char *cname;
|
||||
if (mHostRecord->addrinfo)
|
||||
cname = PR_GetCanonNameFromAddrInfo(mHostRecord->addrinfo);
|
||||
else
|
||||
cname = mHostRecord->host;
|
||||
result.Assign(cname);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSRecord::GetNextAddr(PRUint16 port, PRNetAddr *addr)
|
||||
{
|
||||
NS_ENSURE_TRUE(mAddrInfo, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
// not a programming error to poke the DNS record when it has
|
||||
// no more entries. just silently fail. this enables consumers
|
||||
// not a programming error to poke the DNS record when it has no more
|
||||
// entries. just fail without any debug warnings. this enables consumers
|
||||
// to enumerate the DNS record without calling HasMore.
|
||||
if (mDone)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
mIter = PR_EnumerateAddrInfo(mIter, mAddrInfo->get(), port, addr);
|
||||
if (mHostRecord->addrinfo) {
|
||||
mIter = PR_EnumerateAddrInfo(mIter, mHostRecord->addrinfo, port, addr);
|
||||
if (!mIter)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
else {
|
||||
mIter = nsnull; // no iterations
|
||||
NS_ASSERTION(mHostRecord->addr, "no addr");
|
||||
memcpy(addr, mHostRecord->addr, sizeof(PRNetAddr));
|
||||
// set given port
|
||||
port = PR_htons(port);
|
||||
if (addr->raw.family == PR_AF_INET)
|
||||
addr->inet.port = port;
|
||||
else
|
||||
addr->ipv6.port = port;
|
||||
}
|
||||
|
||||
mDone = !mIter;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -121,7 +141,17 @@ nsDNSRecord::GetNextAddrAsString(nsACString &result)
|
|||
NS_IMETHODIMP
|
||||
nsDNSRecord::HasMore(PRBool *result)
|
||||
{
|
||||
*result = !mDone;
|
||||
if (mDone)
|
||||
*result = PR_FALSE;
|
||||
else {
|
||||
// unfortunately, NSPR does not provide a way for us to determine if
|
||||
// there is another address other than to simply get the next address.
|
||||
void *iterCopy = mIter;
|
||||
PRNetAddr addr;
|
||||
*result = NS_SUCCEEDED(GetNextAddr(0, &addr));
|
||||
mIter = iterCopy; // backup iterator
|
||||
mDone = PR_FALSE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -135,7 +165,7 @@ nsDNSRecord::Rewind()
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsDNSAsyncRequest : public nsResolveHostCB
|
||||
class nsDNSAsyncRequest : public nsResolveHostCallback
|
||||
, public nsIDNSRequest
|
||||
{
|
||||
public:
|
||||
|
@ -150,7 +180,7 @@ public:
|
|||
, mListener(listener) {}
|
||||
virtual ~nsDNSAsyncRequest() {}
|
||||
|
||||
void OnLookupComplete(nsHostResolver *, const char *, nsresult, nsAddrInfo *);
|
||||
void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult);
|
||||
|
||||
nsRefPtr<nsHostResolver> mResolver;
|
||||
nsCString mHost; // hostname we're resolving
|
||||
|
@ -159,15 +189,16 @@ public:
|
|||
|
||||
void
|
||||
nsDNSAsyncRequest::OnLookupComplete(nsHostResolver *resolver,
|
||||
const char *host,
|
||||
nsresult status,
|
||||
nsAddrInfo *ai)
|
||||
nsHostRecord *hostRecord,
|
||||
nsresult status)
|
||||
{
|
||||
nsDNSRecord *rec;
|
||||
if (!ai)
|
||||
rec = nsnull;
|
||||
else {
|
||||
rec = new nsDNSRecord(ai);
|
||||
// need to have an owning ref when we issue the callback to enable
|
||||
// the caller to be able to addref/release multiple times without
|
||||
// destroying the record prematurely.
|
||||
nsCOMPtr<nsIDNSRecord> rec;
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
NS_ASSERTION(hostRecord, "no host record");
|
||||
rec = new nsDNSRecord(hostRecord);
|
||||
if (!rec)
|
||||
status = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -191,7 +222,7 @@ nsDNSAsyncRequest::Cancel()
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsDNSSyncRequest : public nsResolveHostCB
|
||||
class nsDNSSyncRequest : public nsResolveHostCallback
|
||||
{
|
||||
public:
|
||||
nsDNSSyncRequest(PRMonitor *mon)
|
||||
|
@ -200,11 +231,11 @@ public:
|
|||
, mMonitor(mon) {}
|
||||
virtual ~nsDNSSyncRequest() {}
|
||||
|
||||
void OnLookupComplete(nsHostResolver *, const char *, nsresult, nsAddrInfo *);
|
||||
void OnLookupComplete(nsHostResolver *, nsHostRecord *, nsresult);
|
||||
|
||||
PRBool mDone;
|
||||
nsresult mStatus;
|
||||
nsRefPtr<nsAddrInfo> mAddrInfo;
|
||||
nsRefPtr<nsHostRecord> mHostRecord;
|
||||
|
||||
private:
|
||||
PRMonitor *mMonitor;
|
||||
|
@ -212,15 +243,14 @@ private:
|
|||
|
||||
void
|
||||
nsDNSSyncRequest::OnLookupComplete(nsHostResolver *resolver,
|
||||
const char *host,
|
||||
nsresult status,
|
||||
nsAddrInfo *ai)
|
||||
nsHostRecord *hostRecord,
|
||||
nsresult status)
|
||||
{
|
||||
// store results, and wake up nsDNSService::Resolve to process results.
|
||||
PR_EnterMonitor(mMonitor);
|
||||
mDone = PR_TRUE;
|
||||
mStatus = status;
|
||||
mAddrInfo = ai;
|
||||
mHostRecord = hostRecord;
|
||||
PR_Notify(mMonitor);
|
||||
PR_ExitMonitor(mMonitor);
|
||||
}
|
||||
|
@ -325,11 +355,10 @@ nsDNSService::AsyncResolve(const nsACString &hostname,
|
|||
const nsACString *hostPtr = &hostname;
|
||||
|
||||
nsresult rv;
|
||||
nsCAutoString hostBuf;
|
||||
nsCAutoString hostACE;
|
||||
if (idn && !IsASCII(hostname)) {
|
||||
rv = idn->ConvertUTF8toACE(hostname, hostBuf);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
hostPtr = &hostBuf;
|
||||
if (NS_SUCCEEDED(idn->ConvertUTF8toACE(hostname, hostACE)))
|
||||
hostPtr = &hostACE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDNSListener> listenerProxy;
|
||||
|
@ -377,11 +406,10 @@ nsDNSService::Resolve(const nsACString &hostname,
|
|||
const nsACString *hostPtr = &hostname;
|
||||
|
||||
nsresult rv;
|
||||
nsCAutoString hostBuf;
|
||||
nsCAutoString hostACE;
|
||||
if (idn && !IsASCII(hostname)) {
|
||||
rv = idn->ConvertUTF8toACE(hostname, hostBuf);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
hostPtr = &hostBuf;
|
||||
if (NS_SUCCEEDED(idn->ConvertUTF8toACE(hostname, hostACE)))
|
||||
hostPtr = &hostACE;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -408,7 +436,8 @@ nsDNSService::Resolve(const nsACString &hostname,
|
|||
if (NS_FAILED(syncReq.mStatus))
|
||||
rv = syncReq.mStatus;
|
||||
else {
|
||||
nsDNSRecord *rec = new nsDNSRecord(syncReq.mAddrInfo);
|
||||
NS_ASSERTION(syncReq.mHostRecord, "no host record");
|
||||
nsDNSRecord *rec = new nsDNSRecord(syncReq.mHostRecord);
|
||||
if (!rec)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else
|
||||
|
|
|
@ -144,32 +144,36 @@ private:
|
|||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class nsHostRecord : public PRCList
|
||||
nsresult
|
||||
nsHostRecord::Create(const char *host, nsHostRecord **result)
|
||||
{
|
||||
public:
|
||||
NET_DECL_REFCOUNTED_THREADSAFE
|
||||
size_t hostLen = strlen(host) + 1;
|
||||
size_t size = hostLen + sizeof(nsHostRecord);
|
||||
|
||||
nsHostRecord(const char *h)
|
||||
: host(PL_strdup(h))
|
||||
, expireTime(NowInMinutes())
|
||||
, mRefCount(0)
|
||||
{
|
||||
PR_INIT_CLIST(this);
|
||||
PR_INIT_CLIST(&callbacks);
|
||||
}
|
||||
~nsHostRecord()
|
||||
{
|
||||
PL_strfree(host);
|
||||
nsHostRecord *rec = (nsHostRecord*) ::operator new(size);
|
||||
if (!rec)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rec->_refc = 1; // addref
|
||||
rec->host = ((char *) rec) + sizeof(nsHostRecord);
|
||||
rec->addrinfo = nsnull;
|
||||
rec->addr = nsnull;
|
||||
rec->expiration = NowInMinutes();
|
||||
PR_INIT_CLIST(rec);
|
||||
PR_INIT_CLIST(&rec->callbacks);
|
||||
memcpy(rec->host, host, hostLen);
|
||||
|
||||
*result = rec;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
char *host;
|
||||
nsRefPtr<nsAddrInfo> addr;
|
||||
PRUint32 expireTime; // minutes since epoch
|
||||
PRCList callbacks;
|
||||
|
||||
private:
|
||||
PRInt32 mRefCount;
|
||||
};
|
||||
nsHostRecord::~nsHostRecord()
|
||||
{
|
||||
if (addrinfo)
|
||||
PR_FreeAddrInfo(addrinfo);
|
||||
if (addr)
|
||||
free(addr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
@ -178,14 +182,14 @@ struct nsHostDBEnt : PLDHashEntryHdr
|
|||
nsHostRecord *rec;
|
||||
};
|
||||
|
||||
static const void * PR_CALLBACK
|
||||
PR_STATIC_CALLBACK(const void *)
|
||||
HostDB_GetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
|
||||
{
|
||||
nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, entry);
|
||||
return he->rec->host;
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
PR_STATIC_CALLBACK(PRBool)
|
||||
HostDB_MatchEntry(PLDHashTable *table,
|
||||
const PLDHashEntryHdr *entry,
|
||||
const void *key)
|
||||
|
@ -194,7 +198,7 @@ HostDB_MatchEntry(PLDHashTable *table,
|
|||
return !strcmp(he->rec->host, (const char *) key);
|
||||
}
|
||||
|
||||
static void PR_CALLBACK
|
||||
PR_STATIC_CALLBACK(void)
|
||||
HostDB_MoveEntry(PLDHashTable *table,
|
||||
const PLDHashEntryHdr *from,
|
||||
PLDHashEntryHdr *to)
|
||||
|
@ -203,25 +207,25 @@ HostDB_MoveEntry(PLDHashTable *table,
|
|||
NS_STATIC_CAST(const nsHostDBEnt *, from)->rec;
|
||||
}
|
||||
|
||||
static void PR_CALLBACK
|
||||
PR_STATIC_CALLBACK(void)
|
||||
HostDB_ClearEntry(PLDHashTable *table,
|
||||
PLDHashEntryHdr *entry)
|
||||
{
|
||||
nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, entry);
|
||||
#ifdef DEBUG_HOST_RESOLVER
|
||||
if (!he->rec->addr)
|
||||
LOG(("%s: => null\n", he->rec->host));
|
||||
if (!he->rec->addrinfo)
|
||||
LOG(("%s: => no addrinfo\n", he->rec->host));
|
||||
else {
|
||||
PRInt32 now = (PRInt32) NowInMinutes();
|
||||
PRInt32 diff = (PRInt32) he->rec->expireTime - now;
|
||||
PRInt32 diff = (PRInt32) he->rec->expiration - now;
|
||||
LOG(("%s: exp=%d => %s\n",
|
||||
he->rec->host, diff,
|
||||
PR_GetCanonNameFromAddrInfo(he->rec->addr->get())));
|
||||
PR_GetCanonNameFromAddrInfo(he->rec->addrinfo)));
|
||||
void *iter = nsnull;
|
||||
PRNetAddr addr;
|
||||
char buf[64];
|
||||
do {
|
||||
iter = PR_EnumerateAddrInfo(iter, he->rec->addr->get(), 0, &addr);
|
||||
iter = PR_EnumerateAddrInfo(iter, he->rec->addrinfo, 0, &addr);
|
||||
PR_NetAddrToString(&addr, buf, sizeof(buf));
|
||||
LOG((" %s\n", buf));
|
||||
} while (iter);
|
||||
|
@ -230,23 +234,13 @@ HostDB_ClearEntry(PLDHashTable *table,
|
|||
NS_RELEASE(he->rec);
|
||||
}
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
PR_STATIC_CALLBACK(PRBool)
|
||||
HostDB_InitEntry(PLDHashTable *table,
|
||||
PLDHashEntryHdr *entry,
|
||||
const void *key)
|
||||
{
|
||||
nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, entry);
|
||||
he->rec = new nsHostRecord(NS_REINTERPRET_CAST(const char *, key));
|
||||
// addref result if initialized correctly; otherwise, leave record
|
||||
// null so caller can detect and propagate error.
|
||||
if (he->rec) {
|
||||
if (he->rec->host)
|
||||
NS_ADDREF(he->rec);
|
||||
else {
|
||||
delete he->rec;
|
||||
he->rec = nsnull;
|
||||
}
|
||||
}
|
||||
nsHostRecord::Create(NS_REINTERPRET_CAST(const char *, key), &he->rec);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -263,7 +257,7 @@ static PLDHashTableOps gHostDB_ops =
|
|||
HostDB_InitEntry,
|
||||
};
|
||||
|
||||
static PLDHashOperator PR_CALLBACK
|
||||
PR_STATIC_CALLBACK(PLDHashOperator)
|
||||
HostDB_RemoveEntry(PLDHashTable *table,
|
||||
PLDHashEntryHdr *hdr,
|
||||
PRUint32 number,
|
||||
|
@ -276,8 +270,7 @@ HostDB_RemoveEntry(PLDHashTable *table,
|
|||
|
||||
nsHostResolver::nsHostResolver(PRUint32 maxCacheEntries,
|
||||
PRUint32 maxCacheLifetime)
|
||||
: mRefCount(0)
|
||||
, mMaxCacheEntries(maxCacheEntries)
|
||||
: mMaxCacheEntries(maxCacheEntries)
|
||||
, mMaxCacheLifetime(maxCacheLifetime)
|
||||
, mLock(nsnull)
|
||||
, mIdleThreadCV(nsnull)
|
||||
|
@ -354,14 +347,21 @@ nsHostResolver::Shutdown()
|
|||
nsresult
|
||||
nsHostResolver::ResolveHost(const char *host,
|
||||
PRBool bypassCache,
|
||||
nsResolveHostCB *callback)
|
||||
nsResolveHostCallback *callback)
|
||||
{
|
||||
NS_ENSURE_TRUE(host && *host, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// if result is set inside the lock, then we need to issue the
|
||||
// callback before returning.
|
||||
nsRefPtr<nsHostRecord> result;
|
||||
nsresult status = NS_OK, rv = NS_OK;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
if (mShutdown)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
rv = NS_ERROR_NOT_INITIALIZED;
|
||||
else {
|
||||
PRNetAddr tempAddr;
|
||||
|
||||
// check to see if there is already an entry for this |host|
|
||||
// in the hash table. if so, then check to see if we can't
|
||||
|
@ -370,28 +370,39 @@ nsHostResolver::ResolveHost(const char *host,
|
|||
// and return. otherwise, add ourselves as first pending
|
||||
// callback, and proceed to do the lookup.
|
||||
|
||||
PLDHashEntryHdr *hdr;
|
||||
nsHostDBEnt *he =
|
||||
NS_STATIC_CAST(nsHostDBEnt *,
|
||||
PL_DHashTableOperate(&mDB, host, PL_DHASH_ADD));
|
||||
|
||||
hdr = PL_DHashTableOperate(&mDB, host, PL_DHASH_ADD);
|
||||
if (!hdr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// if the record is null, then HostDB_InitEntry failed.
|
||||
if (!he || !he->rec)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, hdr);
|
||||
if (!he->rec)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// do we have a cached result that we can reuse?
|
||||
else if (!bypassCache &&
|
||||
he->rec->addr && NowInMinutes() <= he->rec->expireTime) {
|
||||
// ok, we can reuse this result. but, since we are
|
||||
// making a callback, we must only do so outside the
|
||||
// lock, and that requires holding an owning reference
|
||||
// to the addrinfo structure.
|
||||
nsRefPtr<nsAddrInfo> ai = he->rec->addr;
|
||||
lock.unlock();
|
||||
callback->OnLookupComplete(this, host, NS_OK, ai);
|
||||
lock.lock();
|
||||
return NS_OK;
|
||||
he->rec->HasResult() &&
|
||||
NowInMinutes() <= he->rec->expiration) {
|
||||
// put reference to host record on stack...
|
||||
result = he->rec;
|
||||
}
|
||||
|
||||
// try parsing the host name as an IP address literal to short
|
||||
// circuit full host resolution. (this is necessary on some
|
||||
// platforms like Win9x. see bug 219376 for more details.)
|
||||
else if (PR_StringToNetAddr(host, &tempAddr) == PR_SUCCESS) {
|
||||
// ok, just copy the result into the host record, and be done
|
||||
// with it! ;-)
|
||||
he->rec->addr = (PRNetAddr *) malloc(sizeof(PRNetAddr));
|
||||
if (!he->rec->addr)
|
||||
status = NS_ERROR_OUT_OF_MEMORY;
|
||||
else
|
||||
memcpy(he->rec->addr, &tempAddr, sizeof(PRNetAddr));
|
||||
// put reference to host record on stack...
|
||||
result = he->rec;
|
||||
}
|
||||
|
||||
// otherwise, hit the resolver...
|
||||
else {
|
||||
PRBool doLookup = PR_CLIST_IS_EMPTY(&he->rec->callbacks);
|
||||
|
||||
// add callback to the list of pending callbacks
|
||||
|
@ -403,14 +414,19 @@ nsHostResolver::ResolveHost(const char *host,
|
|||
if (NS_FAILED(rv))
|
||||
PR_REMOVE_AND_INIT_LINK(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result)
|
||||
callback->OnLookupComplete(this, result, status);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsHostResolver::DetachCallback(const char *host,
|
||||
nsResolveHostCB *callback)
|
||||
nsResolveHostCallback *callback)
|
||||
{
|
||||
PRBool doCallback = PR_FALSE;
|
||||
nsRefPtr<nsHostRecord> rec;
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
|
@ -421,9 +437,9 @@ nsHostResolver::DetachCallback(const char *host,
|
|||
// that it will be there!
|
||||
PRCList *node = he->rec->callbacks.next;
|
||||
while (node != &he->rec->callbacks) {
|
||||
if (NS_STATIC_CAST(nsResolveHostCB *, node) == callback) {
|
||||
if (NS_STATIC_CAST(nsResolveHostCallback *, node) == callback) {
|
||||
PR_REMOVE_LINK(callback);
|
||||
doCallback = PR_TRUE;
|
||||
rec = he->rec;
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
|
@ -431,8 +447,10 @@ nsHostResolver::DetachCallback(const char *host,
|
|||
}
|
||||
}
|
||||
|
||||
if (doCallback)
|
||||
callback->OnLookupComplete(this, host, NS_ERROR_ABORT, nsnull);
|
||||
// complete callback with an error code; this would only be done
|
||||
// if the record was in the process of being resolved.
|
||||
if (rec)
|
||||
callback->OnLookupComplete(this, rec, NS_ERROR_ABORT);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -501,17 +519,6 @@ nsHostResolver::GetHostToLookup(nsHostRecord **result)
|
|||
void
|
||||
nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, PRAddrInfo *result)
|
||||
{
|
||||
nsAddrInfo *ai;
|
||||
if (!result)
|
||||
ai = nsnull;
|
||||
else {
|
||||
ai = new nsAddrInfo(result);
|
||||
if (!ai) {
|
||||
status = NS_ERROR_OUT_OF_MEMORY;
|
||||
PR_FreeAddrInfo(result);
|
||||
}
|
||||
}
|
||||
|
||||
// get the list of pending callbacks for this lookup, and notify
|
||||
// them that the lookup is complete.
|
||||
PRCList cbs;
|
||||
|
@ -519,11 +526,14 @@ nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, PRAddrInfo
|
|||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
// grab list of callbacks to notify
|
||||
MoveCList(rec->callbacks, cbs);
|
||||
rec->addr = ai;
|
||||
rec->expireTime = NowInMinutes() + mMaxCacheLifetime;
|
||||
|
||||
if (rec->addr) {
|
||||
// update record fields
|
||||
rec->addrinfo = result;
|
||||
rec->expiration = NowInMinutes() + mMaxCacheLifetime;
|
||||
|
||||
if (rec->addrinfo) {
|
||||
// add to mEvictionQ
|
||||
PR_APPEND_LINK(rec, &mEvictionQ);
|
||||
NS_ADDREF(rec);
|
||||
|
@ -544,9 +554,10 @@ nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, PRAddrInfo
|
|||
if (!PR_CLIST_IS_EMPTY(&cbs)) {
|
||||
PRCList *node = cbs.next;
|
||||
while (node != &cbs) {
|
||||
nsResolveHostCB *callback = NS_STATIC_CAST(nsResolveHostCB *, node);
|
||||
nsResolveHostCallback *callback =
|
||||
NS_STATIC_CAST(nsResolveHostCallback *, node);
|
||||
node = node->next;
|
||||
callback->OnLookupComplete(this, rec->host, status, ai);
|
||||
callback->OnLookupComplete(this, rec, status);
|
||||
// NOTE: callback must not be dereferenced after this point!!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,83 +43,101 @@
|
|||
#include "prclist.h"
|
||||
#include "prnetdb.h"
|
||||
#include "pldhash.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
class nsHostResolver;
|
||||
class nsHostRecord;
|
||||
class nsResolveHostCB;
|
||||
class nsAddrInfo;
|
||||
class nsResolveHostCallback;
|
||||
|
||||
/* XXX move this someplace more generic */
|
||||
#define NET_DECL_REFCOUNTED_THREADSAFE \
|
||||
#define NS_DECL_REFCOUNTED_THREADSAFE \
|
||||
private: \
|
||||
nsAutoRefCnt _refc; \
|
||||
public: \
|
||||
PRInt32 AddRef() { \
|
||||
return PR_AtomicIncrement(&mRefCount); \
|
||||
return PR_AtomicIncrement((PRInt32*)&_refc); \
|
||||
} \
|
||||
PRInt32 Release() { \
|
||||
PRInt32 n = PR_AtomicDecrement(&mRefCount); \
|
||||
PRInt32 n = PR_AtomicDecrement((PRInt32*)&_refc); \
|
||||
if (n == 0) \
|
||||
delete this; \
|
||||
return n; \
|
||||
}
|
||||
|
||||
/**
|
||||
* reference counted wrapper around PRAddrInfo. these are stored in
|
||||
* the DNS cache.
|
||||
* nsHostRecord - ref counted object type stored in host resolver cache.
|
||||
*/
|
||||
class nsAddrInfo
|
||||
class nsHostRecord : public PRCList
|
||||
{
|
||||
public:
|
||||
NET_DECL_REFCOUNTED_THREADSAFE
|
||||
NS_DECL_REFCOUNTED_THREADSAFE
|
||||
|
||||
nsAddrInfo(PRAddrInfo *data)
|
||||
: mRefCount(0)
|
||||
, mData(data) {}
|
||||
/* instantiates a new host record */
|
||||
static nsresult Create(const char *host, nsHostRecord **record);
|
||||
|
||||
const PRAddrInfo *get() const { return mData; }
|
||||
/* a fully resolved host record has either a non-null |addrinfo| or |addr|
|
||||
* field. if |addrinfo| is null, it implies that the |host| is an IP
|
||||
* address literal. in which case, |addr| contains the parsed address.
|
||||
* otherwise, if |addrinfo| is non-null, then it contains one or many
|
||||
* IP addresses corresponding to the given host name. if both |addrinfo|
|
||||
* and |addr| are null, then the given host has not yet been fully resolved.
|
||||
*/
|
||||
char *host;
|
||||
PRAddrInfo *addrinfo;
|
||||
PRNetAddr *addr;
|
||||
|
||||
PRBool HasResult() const { return (addrinfo || addr) != nsnull; }
|
||||
|
||||
private:
|
||||
nsAddrInfo(); // never called
|
||||
~nsAddrInfo() { if (mData) PR_FreeAddrInfo(mData); }
|
||||
friend class nsHostResolver;
|
||||
|
||||
PRInt32 mRefCount;
|
||||
PRAddrInfo *mData;
|
||||
/* these fields are used internally by the host resolver */
|
||||
PRUint32 expiration; /* measured in minutes since epoch */
|
||||
PRCList callbacks;
|
||||
|
||||
~nsHostRecord();
|
||||
};
|
||||
|
||||
/**
|
||||
* ResolveHost callback object. It's PRCList members are used by
|
||||
* the nsHostResolver and should not be used by anything else.
|
||||
*/
|
||||
class nsResolveHostCB : public PRCList
|
||||
class NS_NO_VTABLE nsResolveHostCallback : public PRCList
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* LookupComplete
|
||||
* OnLookupComplete
|
||||
*
|
||||
* Runs on an unspecified background thread.
|
||||
* 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 host
|
||||
* hostname that was resolved
|
||||
* @param record
|
||||
* the host record containing the results of the lookup
|
||||
* @param status
|
||||
* if successful, |result| will be non-null
|
||||
* @param result
|
||||
* resulting nsAddrInfo object
|
||||
* if successful, |record| contains non-null results
|
||||
*/
|
||||
virtual void OnLookupComplete(nsHostResolver *resolver,
|
||||
const char *host,
|
||||
nsresult status,
|
||||
nsAddrInfo *result) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~nsResolveHostCB() {}
|
||||
nsHostRecord *record,
|
||||
nsresult status) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* nsHostResolver: an asynchronous hostname resolver.
|
||||
* nsHostResolver - an asynchronous host name resolver.
|
||||
*/
|
||||
class nsHostResolver
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* host resolver instances are reference counted.
|
||||
*/
|
||||
NS_DECL_REFCOUNTED_THREADSAFE
|
||||
|
||||
/**
|
||||
* creates an addref'd instance of a nsHostResolver object.
|
||||
*/
|
||||
|
@ -133,11 +151,6 @@ public:
|
|||
*/
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* host resolver instances are reference counted.
|
||||
*/
|
||||
NET_DECL_REFCOUNTED_THREADSAFE
|
||||
|
||||
/**
|
||||
* resolve the given hostname asynchronously. the caller can synthesize
|
||||
* a synchronous host lookup using a lock and a cvar. as noted above
|
||||
|
@ -147,7 +160,7 @@ public:
|
|||
*/
|
||||
nsresult ResolveHost(const char *hostname,
|
||||
PRBool bypassCache,
|
||||
nsResolveHostCB *callback);
|
||||
nsResolveHostCallback *callback);
|
||||
|
||||
/**
|
||||
* removes the specified callback from the nsHostRecord for the given
|
||||
|
@ -155,7 +168,7 @@ public:
|
|||
* still pending with the status failure code NS_ERROR_ABORT.
|
||||
*/
|
||||
void DetachCallback(const char *hostname,
|
||||
nsResolveHostCB *callback);
|
||||
nsResolveHostCallback *callback);
|
||||
|
||||
private:
|
||||
nsHostResolver(PRUint32 maxCacheEntries=50, PRUint32 maxCacheLifetime=1);
|
||||
|
@ -166,9 +179,8 @@ private:
|
|||
PRBool GetHostToLookup(nsHostRecord **);
|
||||
void OnLookupComplete(nsHostRecord *, nsresult, PRAddrInfo *);
|
||||
|
||||
static void PR_CALLBACK ThreadFunc(void *);
|
||||
PR_STATIC_CALLBACK(void) ThreadFunc(void *);
|
||||
|
||||
PRInt32 mRefCount;
|
||||
PRUint32 mMaxCacheEntries;
|
||||
PRUint32 mMaxCacheLifetime;
|
||||
PRLock *mLock;
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
nsIDNSRecord *rec,
|
||||
nsresult status)
|
||||
{
|
||||
printf("%d: OnLookupComplete called [host=%s status=%x ai=%p]\n",
|
||||
printf("%d: OnLookupComplete called [host=%s status=%x rec=%p]\n",
|
||||
mIndex, mHost.get(), status, (void*)rec);
|
||||
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
|
@ -69,9 +69,12 @@ public:
|
|||
rec->GetCanonicalName(buf);
|
||||
printf("%d: canonname=%s\n", mIndex, buf.get());
|
||||
|
||||
while (NS_SUCCEEDED(rec->GetNextAddrAsString(buf)))
|
||||
PRBool hasMore;
|
||||
while (NS_SUCCEEDED(rec->HasMore(&hasMore)) && hasMore) {
|
||||
rec->GetNextAddrAsString(buf);
|
||||
printf("%d: => %s\n", mIndex, buf.get());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -113,7 +116,10 @@ int main(int argc, char **argv)
|
|||
|
||||
nsCOMPtr<nsIDNSListener> listener = new myDNSListener(argv[i], i);
|
||||
nsCOMPtr<nsIDNSRequest> req;
|
||||
dns->AsyncResolve(hostBuf, PR_FALSE, listener, nsnull, getter_AddRefs(req));
|
||||
nsresult rv = dns->AsyncResolve(hostBuf, PR_FALSE, listener, nsnull,
|
||||
getter_AddRefs(req));
|
||||
if (NS_FAILED(rv))
|
||||
printf("### AsyncResolve failed [rv=%x]\n", rv);
|
||||
}
|
||||
|
||||
printf("main thread sleeping for %d seconds...\n", sleepLen);
|
||||
|
|
Загрузка…
Ссылка в новой задаче