Back to index

lightning-sunbird  0.9+nobinonly
Functions | Variables
nsLDAPConnection.cpp File Reference
#include "nsLDAPInternal.h"
#include "nsIServiceManager.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsIComponentManager.h"
#include "nsLDAPConnection.h"
#include "nsLDAPMessage.h"
#include "nsIEventQueueService.h"
#include "nsIConsoleService.h"
#include "nsIDNSService.h"
#include "nsIDNSRecord.h"
#include "nsIRequestObserver.h"
#include "nsIProxyObjectManager.h"
#include "nsEventQueueUtils.h"
#include "nsNetError.h"
#include "nsLDAPOperation.h"

Go to the source code of this file.

Functions

NS_INTERFACE_MAP_END_THREADSAFE NS_IMPL_CI_INTERFACE_GETTER3 (nsLDAPConnection, nsILDAPConnection, nsISupportsWeakReference, nsIDNSListener) nsrefcnt nsLDAPConnection
PRBool PR_CALLBACK CheckLDAPOperationResult (nsHashKey *aKey, void *aData, void *aClosure)

Variables

const char kConsoleServiceContractId [] = "@mozilla.org/consoleservice;1"
const char kDNSServiceContractId [] = "@mozilla.org/network/dns-service;1"

Function Documentation

PRBool PR_CALLBACK CheckLDAPOperationResult ( nsHashKey *  aKey,
void aData,
void aClosure 
)

Definition at line 597 of file nsLDAPConnection.cpp.

{
    int lderrno;
    nsresult rv;
    PRInt32 returnCode;
    LDAPMessage *msgHandle;
    nsCOMPtr<nsILDAPMessage> msg;
    PRBool operationFinished = PR_TRUE;
    struct timeval timeout = { 1, 0 }; 
    PRIntervalTime sleepTime = PR_MillisecondsToInterval(40);

    // we need to access some of the connection loop's objects
    //
    nsLDAPConnectionLoop *loop = 
        NS_STATIC_CAST(nsLDAPConnectionLoop *, aClosure);

    // get the console service so we can log messages
    //
    nsCOMPtr<nsIConsoleService> consoleSvc = 
        do_GetService(kConsoleServiceContractId, &rv);
    if (NS_FAILED(rv)) {
        NS_ERROR("CheckLDAPOperationResult() couldn't get console service");
        return NS_ERROR_FAILURE;
    }

    returnCode = ldap_result(loop->mRawConn->mConnectionHandle,
                             aKey->HashCode(), LDAP_MSG_ONE,
                                 &timeout, &msgHandle);

        // if we didn't error or timeout, create an nsILDAPMessage
        //      
        switch (returnCode) {

        case 0: // timeout

            // the connection may not exist yet.  sleep for a while
            // to avoid a problem where the LDAP connection/thread isn't 
            // ready quite yet, and we want to avoid a very busy loop.
            //
            PR_Sleep(sleepTime);
            return PR_TRUE;

        case -1: // something went wrong 

        lderrno = ldap_get_lderrno(loop->mRawConn->mConnectionHandle, 0, 0);

            // Sleep briefly, to avoid a very busy loop again.
            //
            PR_Sleep(sleepTime);

            switch (lderrno) {

            case LDAP_SERVER_DOWN:
                // We might want to shutdown the thread here, but it has
                // implications to the user of the nsLDAPConnection, so
                // for now we just ignore it. It's up to the owner of
                // the nsLDAPConnection to detect the error, and then
                // create a new connection.
                //
                PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, 
                       ("CheckLDAPOperationResult(): ldap_result returned" 
                        " LDAP_SERVER_DOWN"));
                break;

            case LDAP_DECODING_ERROR:
                consoleSvc->LogStringMessage(
                    NS_LITERAL_STRING("LDAP: WARNING: decoding error; possible corrupt data received").get());
                NS_WARNING("CheckLDAPOperationResult(): ldaperrno = "
                           "LDAP_DECODING_ERROR after ldap_result()");
                break;

            case LDAP_NO_MEMORY:
                NS_ERROR("CheckLDAPOperationResult(): Couldn't allocate memory"
                         " while getting async operation result");
                // punt and hope things work out better next time around
                break;

            case LDAP_PARAM_ERROR:
                // I think it's possible to hit a race condition where we're
                // continuing to poll for a result after the C SDK connection
                // has removed the operation because the connection has gone
                // dead.  In theory we should fix this.  Practically, it's
                // unclear to me whether it matters.
                //
                NS_WARNING("CheckLDAPOperationResult(): ldap_result returned"
                           " LDAP_PARAM_ERROR");
                break;

            default:
                NS_ERROR("CheckLDAPOperationResult(): lderrno set to "
                           "unexpected value after ldap_result() "
                           "call in nsLDAPConnection::Run()");
                PR_LOG(gLDAPLogModule, PR_LOG_ERROR, 
                       ("lderrno = 0x%x", lderrno));
                break;
            }
            break;

        case LDAP_RES_SEARCH_ENTRY:
        case LDAP_RES_SEARCH_REFERENCE:
            // XXX what should we do with LDAP_RES_SEARCH_EXTENDED?

            // not done yet, so we shouldn't remove the op from the conn q
            operationFinished = PR_FALSE;

            // fall through to default case

        default: // initialize the message and call the callback

            // we want nsLDAPMessage specifically, not a compatible, since
            // we're sharing native objects used by the LDAP C SDK
            //
            nsLDAPMessage *rawMsg;
            NS_NEWXPCOM(rawMsg, nsLDAPMessage);
            if (!rawMsg) {
            NS_ERROR("CheckLDAPOperationResult(): couldn't allocate memory"
                     " for new LDAP message; search entry dropped");
                // punt and hope things work out better next time around
                break;
            }

            // initialize the message, using a protected method not available
            // through nsILDAPMessage (which is why we need the raw pointer)
            //
            rv = rawMsg->Init(loop->mRawConn, msgHandle);

            switch (rv) {

            case NS_OK: {
                PRInt32 errorCode;
                rawMsg->GetErrorCode(&errorCode);
                // maybe a version error, e.g., using v3 on a v2 server.
                // if we're using v3, try v2.
                //
                if (errorCode == LDAP_PROTOCOL_ERROR && 
                   loop->mRawConn->mVersion == nsILDAPConnection::VERSION3) {
                    nsCAutoString password;
                    loop->mRawConn->mVersion = nsILDAPConnection::VERSION2;
                    ldap_set_option(loop->mRawConn->mConnectionHandle,
                          LDAP_OPT_PROTOCOL_VERSION, &loop->mRawConn->mVersion);
                    nsCOMPtr <nsILDAPOperation> operation = 
                      NS_STATIC_CAST(nsILDAPOperation *, 
                          NS_STATIC_CAST(nsISupports *, aData));
                    // we pass in an empty password to tell the operation that 
                    // it should use the cached password.
                    //
                    rv = operation->SimpleBind(password);
                    if (NS_SUCCEEDED(rv)) {
                        operationFinished = PR_FALSE;
                        // we don't want to notify callers that we're done...
                        return PR_TRUE;
                    }
                }
            }
            break;

            case NS_ERROR_LDAP_DECODING_ERROR:
                consoleSvc->LogStringMessage(
                    NS_LITERAL_STRING("LDAP: WARNING: decoding error; possible corrupt data received").get());
            NS_WARNING("CheckLDAPOperationResult(): ldaperrno = "
                           "LDAP_DECODING_ERROR after ldap_result()");
            return PR_TRUE;

            case NS_ERROR_OUT_OF_MEMORY:
                // punt and hope things work out better next time around
            return PR_TRUE;

            case NS_ERROR_ILLEGAL_VALUE:
            case NS_ERROR_UNEXPECTED:
            default:
                // shouldn't happen; internal error
                //
            NS_ERROR("CheckLDAPOperationResult(): nsLDAPMessage::Init() "
                           "returned unexpected value.");

                // punt and hope things work out better next time around
            return PR_TRUE;
            }

            // now let the scoping mechanisms provided by nsCOMPtr manage
            // the reference for us.
            //
            msg = rawMsg;

            // invoke the callback on the nsILDAPOperation corresponding to 
            // this message
            //
        rv = loop->mRawConn->InvokeMessageCallback(msgHandle, msg, 
                                                    operationFinished);
            if (NS_FAILED(rv)) {
            NS_ERROR("CheckLDAPOperationResult(): error invoking message"
                     " callback");
                // punt and hope things work out better next time around
            return PR_TRUE;
            }

            break;
        }       

    return PR_TRUE;
}

Here is the call graph for this function:

Definition at line 101 of file nsLDAPConnection.cpp.

{
    nsrefcnt count;

    NS_PRECONDITION(0 != mRefCnt, "dup release");
    count = PR_AtomicDecrement((PRInt32 *)&mRefCnt);
    NS_LOG_RELEASE(this, count, "nsLDAPConnection");
    if (0 == count) {
        // As commented by danm: In the object's destructor, if by some
        // convoluted, indirect means it happens to run into some code
        // that temporarily references it (addref/release), then if the
        // refcount had been left at 0 the unexpected release would
        // attempt to reenter the object's destructor.
        //
        mRefCnt = 1; /* stabilize */

        // If we have a mRunnable object, we need to make sure to lock it's
        // mLock before we try to DELETE. This is to avoid a race condition.
        // We also make sure to keep a strong reference to the runnable
        // object, to make sure it doesn't get GCed from underneath us,
        // while we are still holding a lock for instance.
        //
        if (mRunnable && mRunnable->mLock) {
            nsLDAPConnectionLoop *runnable  = mRunnable;

            NS_ADDREF(runnable);
            PR_Lock(runnable->mLock);
            NS_DELETEXPCOM(this);
            PR_Unlock(runnable->mLock);
            NS_RELEASE(runnable);
        } else {
            NS_DELETEXPCOM(this);
        }

        return 0;
    }
    return count;
}

Here is the call graph for this function:


Variable Documentation

const char kConsoleServiceContractId[] = "@mozilla.org/consoleservice;1"

Definition at line 62 of file nsLDAPConnection.cpp.

const char kDNSServiceContractId[] = "@mozilla.org/network/dns-service;1"

Definition at line 63 of file nsLDAPConnection.cpp.