Back to index

lightning-sunbird  0.9+nobinonly
Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes
nsHostResolver Class Reference

nsHostResolver - an asynchronous host name resolver. More...

#include <nsHostResolver.h>

Collaboration diagram for nsHostResolver:
Collaboration graph
[legend]

List of all members.

Public Types

enum  { RES_BYPASS_CACHE = 1 << 0, RES_CANON_NAME = 1 << 1 }
 values for the flags parameter passed to ResolveHost and DetachCallback that may be bitwise OR'd together. More...

Public Member Functions

void Shutdown ()
 puts the resolver in the shutdown state, which will cause any pending callbacks to be detached.
nsresult ResolveHost (const char *hostname, PRUint16 flags, PRUint16 af, nsResolveHostCallback *callback)
 resolve the given hostname asynchronously.
void DetachCallback (const char *hostname, PRUint16 flags, PRUint16 af, nsResolveHostCallback *callback, nsresult status)
 removes the specified callback from the nsHostRecord for the given hostname, flags, and address family.

Static Public Member Functions

static
NS_DECL_REFCOUNTED_THREADSAFE
nsresult 
Create (PRUint32 maxCacheEntries, PRUint32 maxCacheLifetime, nsHostResolver **resolver)
 host resolver instances are reference counted.

Private Member Functions

 nsHostResolver (PRUint32 maxCacheEntries=50, PRUint32 maxCacheLifetime=1)
 ~nsHostResolver ()
nsresult Init ()
nsresult IssueLookup (nsHostRecord *)
PRBool GetHostToLookup (nsHostRecord **)
void OnLookupComplete (nsHostRecord *, nsresult, PRAddrInfo *)
 PR_STATIC_CALLBACK (void) ThreadFunc(void *)

Private Attributes

PRUint32 mMaxCacheEntries
PRUint32 mMaxCacheLifetime
PRLockmLock
PRCondVarmIdleThreadCV
PRBool mHaveIdleThread
PRUint32 mThreadCount
PLDHashTable mDB
PRCList mPendingQ
PRCList mEvictionQ
PRUint32 mEvictionQSize
PRTime mCreationTime
PRBool mShutdown

Detailed Description

nsHostResolver - an asynchronous host name resolver.

Definition at line 145 of file nsHostResolver.h.


Member Enumeration Documentation

anonymous enum

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.

Enumerator:
RES_BYPASS_CACHE 
RES_CANON_NAME 

Definition at line 197 of file nsHostResolver.h.

         {
        RES_BYPASS_CACHE = 1 << 0,
        RES_CANON_NAME   = 1 << 1
    };

Constructor & Destructor Documentation

nsHostResolver::nsHostResolver ( PRUint32  maxCacheEntries = 50,
PRUint32  maxCacheLifetime = 1 
) [private]

Definition at line 301 of file nsHostResolver.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 317 of file nsHostResolver.cpp.

Here is the call graph for this function:


Member Function Documentation

nsresult nsHostResolver::Create ( PRUint32  maxCacheEntries,
PRUint32  maxCacheLifetime,
nsHostResolver **  resolver 
) [static]

host resolver instances are reference counted.

creates an addref'd instance of a nsHostResolver object.

Definition at line 665 of file nsHostResolver.cpp.

{
#if defined(PR_LOGGING)
    if (!gHostResolverLog)
        gHostResolverLog = PR_NewLogModule("nsHostResolver");
#endif

    nsHostResolver *res = new nsHostResolver(maxCacheEntries,
                                             maxCacheLifetime);
    if (!res)
        return NS_ERROR_OUT_OF_MEMORY;
    NS_ADDREF(res);

    nsresult rv = res->Init();
    if (NS_FAILED(rv))
        NS_RELEASE(res);

    *result = res;
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsHostResolver::DetachCallback ( const char *  hostname,
PRUint16  flags,
PRUint16  af,
nsResolveHostCallback *  callback,
nsresult  status 
)

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.

Definition at line 463 of file nsHostResolver.cpp.

{
    nsRefPtr<nsHostRecord> rec;
    {
        nsAutoLock lock(mLock);

        nsHostKey key = { host, flags, af };
        nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *,
                PL_DHashTableOperate(&mDB, &key, PL_DHASH_LOOKUP));
        if (he && he->rec) {
            // walk list looking for |callback|... we cannot assume
            // that it will be there!
            PRCList *node = he->rec->callbacks.next;
            while (node != &he->rec->callbacks) {
                if (NS_STATIC_CAST(nsResolveHostCallback *, node) == callback) {
                    PR_REMOVE_LINK(callback);
                    rec = he->rec;
                    break;
                }
                node = node->next;
            }
        }
    }

    // complete callback with the given status code; this would only be done if
    // the record was in the process of being resolved.
    if (rec)
        callback->OnLookupComplete(this, rec, status);
}

Here is the call graph for this function:

Definition at line 540 of file nsHostResolver.cpp.

{
    nsAutoLock lock(mLock);

    PRIntervalTime start = PR_IntervalNow(), timeout = IDLE_TIMEOUT;
    //
    // wait for one or more of the following to occur:
    //  (1) the pending queue has a host record to process
    //  (2) the shutdown flag has been set
    //  (3) the thread has been idle for too long
    //
    // PR_WaitCondVar will return when any of these conditions is true.
    //
    while (PR_CLIST_IS_EMPTY(&mPendingQ) && !mHaveIdleThread && !mShutdown) {
        // become the idle thread and wait for a lookup
        mHaveIdleThread = PR_TRUE;
        PR_WaitCondVar(mIdleThreadCV, timeout);
        mHaveIdleThread = PR_FALSE;

        PRIntervalTime delta = PR_IntervalNow() - start;
        if (delta >= timeout)
            break;
        timeout -= delta;
        start += delta;
    }

    if (!PR_CLIST_IS_EMPTY(&mPendingQ)) {
        // remove next record from mPendingQ; hand over owning reference.
        *result = NS_STATIC_CAST(nsHostRecord *, mPendingQ.next);
        PR_REMOVE_AND_INIT_LINK(*result);
        return PR_TRUE;
    }

    // tell thread to exit...
    mThreadCount--;
    return PR_FALSE;
}

Here is the call graph for this function:

Definition at line 329 of file nsHostResolver.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 498 of file nsHostResolver.cpp.

{
    NS_ASSERTION(!rec->resolving, "record is already being resolved"); 

    // add rec to mPendingQ, possibly removing it from mEvictionQ.
    // if rec is on mEvictionQ, then we can just move the owning
    // reference over to mPendingQ.
    if (rec->next == rec)
        NS_ADDREF(rec);
    else {
        PR_REMOVE_LINK(rec);
        mEvictionQSize--;
    }
    PR_APPEND_LINK(rec, &mPendingQ);
    rec->resolving = PR_TRUE;

    if (mHaveIdleThread) {
        // wake up idle thread to process this lookup
        PR_NotifyCondVar(mIdleThreadCV);
    }
    else if (mThreadCount < MAX_THREADS) {
        // dispatch new worker thread
        NS_ADDREF_THIS(); // owning reference passed to thread
        mThreadCount++;
        PRThread *thr = PR_CreateThread(PR_SYSTEM_THREAD,
                                        ThreadFunc,
                                        this,
                                        PR_PRIORITY_NORMAL,
                                        PR_GLOBAL_THREAD,
                                        PR_UNJOINABLE_THREAD,
                                        0);
        if (!thr) {
            mThreadCount--;
            NS_RELEASE_THIS();
            return NS_ERROR_OUT_OF_MEMORY;
        }
    }

    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsHostResolver::OnLookupComplete ( nsHostRecord rec,
nsresult  status,
PRAddrInfo result 
) [private]

Definition at line 579 of file nsHostResolver.cpp.

{
    // get the list of pending callbacks for this lookup, and notify
    // them that the lookup is complete.
    PRCList cbs;
    PR_INIT_CLIST(&cbs);
    {
        nsAutoLock lock(mLock);

        // grab list of callbacks to notify
        MoveCList(rec->callbacks, cbs);

        // update record fields
        rec->addr_info = result;
        rec->expiration = NowInMinutes() + mMaxCacheLifetime;
        rec->resolving = PR_FALSE;
        
        if (rec->addr_info) {
            // add to mEvictionQ
            PR_APPEND_LINK(rec, &mEvictionQ);
            NS_ADDREF(rec);
            if (mEvictionQSize < mMaxCacheEntries)
                mEvictionQSize++;
            else {
                // remove first element on mEvictionQ
                nsHostRecord *head =
                    NS_STATIC_CAST(nsHostRecord *, PR_LIST_HEAD(&mEvictionQ));
                PR_REMOVE_AND_INIT_LINK(head);
                PL_DHashTableOperate(&mDB, (nsHostKey *) head, PL_DHASH_REMOVE);
                // release reference to rec owned by mEvictionQ
                NS_RELEASE(head);
            }
        }
    }

    if (!PR_CLIST_IS_EMPTY(&cbs)) {
        PRCList *node = cbs.next;
        while (node != &cbs) {
            nsResolveHostCallback *callback =
                    NS_STATIC_CAST(nsResolveHostCallback *, node);
            node = node->next;
            callback->OnLookupComplete(this, rec, status);
            // NOTE: callback must not be dereferenced after this point!!
        }
    }

    NS_RELEASE(rec);
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsHostResolver::ResolveHost ( const char *  hostname,
PRUint16  flags,
PRUint16  af,
nsResolveHostCallback *  callback 
)

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).

Definition at line 378 of file nsHostResolver.cpp.

{
    NS_ENSURE_TRUE(host && *host, NS_ERROR_UNEXPECTED);

    LOG(("nsHostResolver::ResolveHost [host=%s]\n", host));

    // ensure that we are working with a valid hostname before proceeding.  see
    // bug 304904 for details.
    if (!net_IsValidHostName(nsDependentCString(host)))
        return NS_ERROR_UNKNOWN_HOST;

    // 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)
            rv = NS_ERROR_NOT_INITIALIZED;
        else {
            PRNetAddr tempAddr;

            // unfortunately, PR_StringToNetAddr does not properly initialize
            // the output buffer in the case of IPv6 input.  see bug 223145.
            memset(&tempAddr, 0, sizeof(PRNetAddr));
            
            // 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
            // just reuse the lookup result.  otherwise, if there are
            // any pending callbacks, then add to pending callbacks queue,
            // and return.  otherwise, add ourselves as first pending
            // callback, and proceed to do the lookup.

            nsHostKey key = { host, flags, af };
            nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *,
                    PL_DHashTableOperate(&mDB, &key, PL_DHASH_ADD));

            // if the record is null, then HostDB_InitEntry failed.
            if (!he || !he->rec)
                rv = NS_ERROR_OUT_OF_MEMORY;
            // do we have a cached result that we can reuse?
            else if (!(flags & RES_BYPASS_CACHE) &&
                     he->rec->HasResult() &&
                     NowInMinutes() <= he->rec->expiration) {
                LOG(("using cached record\n"));
                // 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 {
                // add callback to the list of pending callbacks
                PR_APPEND_LINK(callback, &he->rec->callbacks);

                if (!he->rec->resolving) {
                    rv = IssueLookup(he->rec);
                    if (NS_FAILED(rv))
                        PR_REMOVE_AND_INIT_LINK(callback);
                }
            }
        }
    }
    if (result)
        callback->OnLookupComplete(this, result, status);
    return rv;
}

Here is the call graph for this function:

puts the resolver in the shutdown state, which will cause any pending callbacks to be detached.

any future calls to ResolveHost will fail.

Definition at line 346 of file nsHostResolver.cpp.

{
    LOG(("nsHostResolver::Shutdown\n"));

    PRCList pendingQ;
    PR_INIT_CLIST(&pendingQ);
    {
        nsAutoLock lock(mLock);
        
        mShutdown = PR_TRUE;

        MoveCList(mPendingQ, pendingQ);

        if (mHaveIdleThread)
            PR_NotifyCondVar(mIdleThreadCV);
        
        // empty host database
        PL_DHashTableEnumerate(&mDB, HostDB_RemoveEntry, nsnull);
    }

    // loop through pending queue, erroring out pending lookups.
    if (!PR_CLIST_IS_EMPTY(&pendingQ)) {
        PRCList *node = pendingQ.next;
        while (node != &pendingQ) {
            nsHostRecord *rec = NS_STATIC_CAST(nsHostRecord *, node);
            node = node->next;
            OnLookupComplete(rec, NS_ERROR_ABORT, nsnull);
        }
    }
}

Here is the call graph for this function:


Member Data Documentation

Definition at line 223 of file nsHostResolver.h.

Definition at line 219 of file nsHostResolver.h.

PRCList nsHostResolver::mEvictionQ [private]

Definition at line 221 of file nsHostResolver.h.

Definition at line 222 of file nsHostResolver.h.

Definition at line 217 of file nsHostResolver.h.

Definition at line 216 of file nsHostResolver.h.

Definition at line 215 of file nsHostResolver.h.

Definition at line 213 of file nsHostResolver.h.

Definition at line 214 of file nsHostResolver.h.

PRCList nsHostResolver::mPendingQ [private]

Definition at line 220 of file nsHostResolver.h.

Definition at line 224 of file nsHostResolver.h.

Definition at line 218 of file nsHostResolver.h.


The documentation for this class was generated from the following files: