Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Public Attributes | Protected Member Functions | Protected Attributes | Friends
nsLDAPConnection Class Reference

#include <nsLDAPConnection.h>

Inheritance diagram for nsLDAPConnection:
Inheritance graph
[legend]
Collaboration diagram for nsLDAPConnection:
Collaboration graph
[legend]

List of all members.

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_NSILDAPCONNECTION
NS_DECL_NSIDNSLISTENER 
nsLDAPConnection ()
virtual ~nsLDAPConnection ()
void init (in string aHost, in long aPort, in boolean aSSL, in AUTF8String aBindName, in nsILDAPMessageListener aMessageListener, in nsISupports aClosure, in unsigned long aVersion)
 Set up the connection.
long getLdErrno (out AUTF8String matched, out AUTF8String s)
 Get information about the last error that occured on this connection.
void onLookupComplete (in nsICancelable aRequest, in nsIDNSRecord aRecord, in nsresult aStatus)
 called when an asynchronous host lookup completes.

Public Attributes

readonly attribute wstring errorString
 the string version of lderrno
readonly attribute AUTF8String bindName
 DN to bind as.
attribute nsISupports closure
 private parameter (anything caller desires)
const unsigned long VERSION2 = 2
const unsigned long VERSION3 = 3

Protected Member Functions

nsresult InvokeMessageCallback (LDAPMessage *aMsgHandle, nsILDAPMessage *aMsg, PRBool aRemoveOpFromConnQ)
nsresult AddPendingOperation (nsILDAPOperation *aOperation)
 Add an nsILDAPOperation to the list of operations pending on this connection.
nsresult RemovePendingOperation (nsILDAPOperation *aOperation)
 Remove an nsILDAPOperation from the list of operations pending on this connection.
void Close ()

Protected Attributes

LDAP * mConnectionHandle
nsCString mBindName
nsCOMPtr< nsIThreadmThread
nsSupportsHashtable * mPendingOperations
nsLDAPConnectionLoopmRunnable
PRInt32 mPort
PRBool mSSL
PRUint32 mVersion
nsCString mResolvedIP
nsCOMPtr< nsILDAPMessageListenermInitListener
nsCOMPtr< nsICancelablemDNSRequest
nsCString mDNSHost
nsCOMPtr< nsISupports > mClosure

Friends

class nsLDAPOperation
class nsLDAPMessage
class nsLDAPConnectionLoop
PRBool PR_CALLBACK CheckLDAPOperationResult (nsHashKey *aKey, void *aData, void *aClosure)

Detailed Description

Definition at line 67 of file nsLDAPConnection.h.


Constructor & Destructor Documentation

Definition at line 79 of file nsLDAPConnection.cpp.

{
  Close();
  // Release the reference to the runnable object.
  //
  NS_IF_RELEASE(mRunnable);
}

Here is the call graph for this function:


Member Function Documentation

Add an nsILDAPOperation to the list of operations pending on this connection.

This is mainly intended for use by the nsLDAPOperation code. Used so that the thread waiting on messages for this connection has an operation to callback to.

Parameters:
aOperationoperation to add
Exceptions:
NS_ERROR_ILLEGAL_VALUEaOperation was NULL
NS_ERROR_UNEXPECTEDthis operation's msgId was not unique to this connection
NS_ERROR_OUT_OF_MEMORYout of memory

This is also mainly intended for use by the nsLDAPOperation code.

Definition at line 370 of file nsLDAPConnection.cpp.

{
    PRInt32 msgID;

    if (!aOperation) {
        return NS_ERROR_ILLEGAL_VALUE;
    }

    // find the message id
    //
    aOperation->GetMessageID(&msgID);

    // turn it into an nsVoidKey.  note that this is another spot that
    // assumes that sizeof(void*) >= sizeof(PRInt32).  
    //
    // XXXdmose  should really create an nsPRInt32Key.
    //
    nsVoidKey *key = new nsVoidKey(NS_REINTERPRET_CAST(void *, msgID));
    if (!key) {
        return NS_ERROR_OUT_OF_MEMORY;
    }

    // actually add it to the queue.  if Put indicates that an item in 
    // the hashtable was actually overwritten, something is really wrong.
    //
    if (mPendingOperations->Put(key, aOperation)) {
        NS_ERROR("nsLDAPConnection::AddPendingOperation() "
                 "mPendingOperations->Put() overwrote an item.  msgId "
                 "is supposed to be unique\n");
        delete key;
        return NS_ERROR_UNEXPECTED;
    }

    PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, 
           ("pending operation added; total pending operations now = %d\n", 
            mPendingOperations->Count()));

    delete key;
    return NS_OK;
}
void nsLDAPConnection::Close ( void  ) [protected]

Definition at line 253 of file nsLDAPConnection.cpp.

{
  int rc;

  PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, ("unbinding\n"));

  if (mConnectionHandle) {
      // note that the ldap_unbind() call in the 5.0 version of the LDAP C SDK
      // appears to be exactly identical to ldap_unbind_s(), so it may in fact
      // still be synchronous
      //
      rc = ldap_unbind(mConnectionHandle);
#ifdef PR_LOGGING
      if (rc != LDAP_SUCCESS) {
          PR_LOG(gLDAPLogModule, PR_LOG_WARNING, 
                 ("nsLDAPConnection::Close(): %s\n", 
                  ldap_err2string(rc)));
      }
#endif
      mConnectionHandle = nsnull;
  }

  PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, ("unbound\n"));

  if (mPendingOperations) {
      delete mPendingOperations;
      mPendingOperations = nsnull;
  }

  // Cancel the DNS lookup if needed, and also drop the reference to the
  // Init listener (if still there).
  //
  if (mDNSRequest) {
      mDNSRequest->Cancel(NS_ERROR_ABORT);
      mDNSRequest = 0;
  }
  mInitListener = 0;

}

Here is the call graph for this function:

Here is the caller graph for this function:

long nsILDAPConnection::getLdErrno ( out AUTF8String  matched,
out AUTF8String  s 
) [inherited]

Get information about the last error that occured on this connection.

Parameters:
matchedif the server is returning LDAP_NO_SUCH_OBJECT, LDAP_ALIAS_PROBLEM, LDAP_INVALID_DN_SYNTAX, or LDAP_ALIAS_DEREF_PROBLEM, this will contain the portion of DN that matches the entry that is closest to the requested entry
sadditional error information from the server
Returns:
the error code, as defined in nsILDAPErrors.idl
void nsILDAPConnection::init ( in string  aHost,
in long  aPort,
in boolean  aSSL,
in AUTF8String  aBindName,
in nsILDAPMessageListener  aMessageListener,
in nsISupports  aClosure,
in unsigned long  aVersion 
) [inherited]

Set up the connection.

Note that init() must be called on a thread that already has an nsIEventQueue.

Parameters:
aHostserver name for ldap_init()
aPortserver port number for ldap_init() -1 == default port (389)
aSSLuse SSL on this connection?
aBindNameDN to bind as
aMessageListenerCallback for DNS resolution completion
aClosureprivate parameter (anything caller desires)
aVersionLDAP version to use (currently VERSION2 or VERSION3)
Exceptions:
NS_ERROR_ILLEGAL_VALUEnull pointer or invalid version
NS_ERROR_OUT_OF_MEMORYran out of memory
NS_ERROR_OFFLINEwe are in off-line mode
NS_ERROR_FAILURE
NS_ERROR_UNEXPECTEDinternal error
nsresult nsLDAPConnection::InvokeMessageCallback ( LDAPMessage *  aMsgHandle,
nsILDAPMessage aMsg,
PRBool  aRemoveOpFromConnQ 
) [protected]

Definition at line 466 of file nsLDAPConnection.cpp.

{
    PRInt32 msgId;
    nsresult rv;
    nsCOMPtr<nsILDAPOperation> operation;
    nsCOMPtr<nsILDAPMessageListener> listener;

#if defined(DEBUG)
    // We only want this being logged for debug builds so as not to affect performance too much.
    PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, ("InvokeMessageCallback entered\n"));
#endif

    // get the message id corresponding to this operation
    //
    msgId = ldap_msgid(aMsgHandle);
    if (msgId == -1) {
        NS_ERROR("nsLDAPConnection::GetCallbackByMessage(): "
                 "ldap_msgid() failed\n");
        return NS_ERROR_FAILURE;
    }

    // get this in key form.  note that using nsVoidKey in this way assumes
    // that sizeof(void *) >= sizeof PRInt32
    //
    nsVoidKey *key = new nsVoidKey(NS_REINTERPRET_CAST(void *, msgId));
    if (!key)
        return NS_ERROR_OUT_OF_MEMORY;

    // find the operation in question
    operation = getter_AddRefs(NS_STATIC_CAST(nsILDAPOperation *, mPendingOperations->Get(key)));
    if (!operation) {

        PR_LOG(gLDAPLogModule, PR_LOG_WARNING, 
               ("Warning: InvokeMessageCallback(): couldn't find "
                "nsILDAPOperation corresponding to this message id\n"));
        delete key;

        // this may well be ok, since it could just mean that the operation
        // was aborted while some number of messages were already in transit.
        //
        return NS_OK;
    }


    // Make sure the mOperation member is set to this operation before
    // we call the callback.
    //
    NS_STATIC_CAST(nsLDAPMessage *, aMsg)->mOperation = operation;

    // get the message listener object (this may be a proxy for a
    // callback which should happen on another thread)
    //
    rv = operation->GetMessageListener(getter_AddRefs(listener));
    if (NS_FAILED(rv)) {
        NS_ERROR("nsLDAPConnection::InvokeMessageCallback(): probable "
                 "memory corruption: GetMessageListener() returned error");
        delete key;
        return NS_ERROR_UNEXPECTED;
    }

    // invoke the callback 
    //
    if (listener) {
      listener->OnLDAPMessage(aMsg);
    }
    // if requested (ie the operation is done), remove the operation
    // from the connection queue.
    //
    if (aRemoveOpFromConnQ) {
        nsCOMPtr <nsLDAPOperation> operation = 
          getter_AddRefs(NS_STATIC_CAST(nsLDAPOperation *,
                                        mPendingOperations->Get(key)));
        // try to break cycles
        if (operation)
          operation->Clear();
        rv = mPendingOperations->Remove(key);
        if (NS_FAILED(rv)) {
            NS_ERROR("nsLDAPConnection::InvokeMessageCallback: unable to "
                     "remove operation from the connection queue\n");
            delete key;
            return NS_ERROR_UNEXPECTED;
        }

        PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, 
               ("pending operation removed; total pending operations now ="
                " %d\n", mPendingOperations->Count()));
    }

    delete key;
    return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsIDNSListener::onLookupComplete ( in nsICancelable  aRequest,
in nsIDNSRecord  aRecord,
in nsresult  aStatus 
) [inherited]

called when an asynchronous host lookup completes.

Parameters:
aRequestthe value returned from asyncResolve.
aRecordthe DNS record corresponding to the hostname that was resolved. this parameter is null if there was an error.
aStatusif the lookup failed, this parameter gives the reason.

Remove an nsILDAPOperation from the list of operations pending on this connection.

Mainly intended for use by the nsLDAPOperation code.

Parameters:
aOperationoperation to add
Exceptions:
NS_ERROR_INVALID_POINTERaOperation was NULL
NS_ERROR_OUT_OF_MEMORYout of memory
NS_ERROR_FAILUREcould not delete the operation

Mainly intended for use by the nsLDAPOperation code.

Parameters:
aOperationoperation to add
Exceptions:
NS_ERROR_INVALID_POINTERaOperation was NULL
NS_ERROR_OUT_OF_MEMORYout of memory
NS_ERROR_FAILUREcould not delete the operation

void removePendingOperation(in nsILDAPOperation aOperation);

Definition at line 423 of file nsLDAPConnection.cpp.

{
    nsresult rv;
    PRInt32 msgID;

    NS_ENSURE_TRUE(mPendingOperations, NS_OK);
    NS_ENSURE_ARG_POINTER(aOperation);

    // find the message id
    //
    rv = aOperation->GetMessageID(&msgID);
    NS_ENSURE_SUCCESS(rv, rv);

    // turn it into an nsVoidKey.  note that this is another spot that
    // assumes that sizeof(void*) >= sizeof(PRInt32).  
    //
    // XXXdmose  should really create an nsPRInt32Key.
    //
    nsVoidKey *key = new nsVoidKey(NS_REINTERPRET_CAST(void *, msgID));
    if (!key) {
        return NS_ERROR_OUT_OF_MEMORY;
    }

    // remove the operation if it's still there.  
    //
    if (!mPendingOperations->Remove(key)) {

        PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, 
               ("nsLDAPConnection::RemovePendingOperation(): could not remove "
                "operation; perhaps it already completed."));
    } else {

        PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, 
               ("nsLDAPConnection::RemovePendingOperation(): operation "
                "removed; total pending operations now = %d\n", 
                mPendingOperations->Count()));
    }

    delete key;
    return NS_OK;
}

Friends And Related Function Documentation

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

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;
}
friend class nsLDAPConnectionLoop [friend]

Definition at line 74 of file nsLDAPConnection.h.

friend class nsLDAPMessage [friend]

Definition at line 73 of file nsLDAPConnection.h.

friend class nsLDAPOperation [friend]

Definition at line 72 of file nsLDAPConnection.h.


Member Data Documentation

readonly attribute AUTF8String nsILDAPConnection::bindName [inherited]

DN to bind as.

use the init() method to set this.

Exceptions:
NS_ERROR_OUT_OF_MEMORY

Definition at line 58 of file nsILDAPConnection.idl.

attribute nsISupports nsILDAPConnection::closure [inherited]

private parameter (anything caller desires)

Definition at line 63 of file nsILDAPConnection.idl.

readonly attribute wstring nsILDAPConnection::errorString [inherited]

the string version of lderrno

Definition at line 51 of file nsILDAPConnection.idl.

Definition at line 123 of file nsLDAPConnection.h.

nsCOMPtr<nsISupports> nsLDAPConnection::mClosure [protected]

Definition at line 137 of file nsLDAPConnection.h.

Definition at line 122 of file nsLDAPConnection.h.

Definition at line 136 of file nsLDAPConnection.h.

Definition at line 135 of file nsLDAPConnection.h.

Definition at line 134 of file nsLDAPConnection.h.

nsSupportsHashtable* nsLDAPConnection::mPendingOperations [protected]

Definition at line 126 of file nsLDAPConnection.h.

Definition at line 129 of file nsLDAPConnection.h.

Definition at line 133 of file nsLDAPConnection.h.

Definition at line 127 of file nsLDAPConnection.h.

Definition at line 130 of file nsLDAPConnection.h.

Definition at line 124 of file nsLDAPConnection.h.

Definition at line 131 of file nsLDAPConnection.h.

const unsigned long nsILDAPConnection::VERSION2 = 2 [inherited]

Definition at line 90 of file nsILDAPConnection.idl.

const unsigned long nsILDAPConnection::VERSION3 = 3 [inherited]

Definition at line 91 of file nsILDAPConnection.idl.


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