Initial implementation and supporting changes for nsLDAPService (bug 70422). Patch from Leif Hedstrom <leif@netscape.com>, r=dmose@netscape.com, sr=brendan@mozilla.org.

This commit is contained in:
dmose%netscape.com 2001-05-05 02:30:50 +00:00
Родитель a05554f8ba
Коммит 0fedea1b41
14 изменённых файлов: 1084 добавлений и 54 удалений

Просмотреть файл

@ -4,4 +4,5 @@ nsILDAPMessage.idl
nsILDAPURL.idl
nsILDAPMessageListener.idl
nsILDAPErrors.idl
nsILDAPServer.idl
nsILDAPServer.idl
nsILDAPService.idl

Просмотреть файл

@ -49,6 +49,7 @@ XPIDLSRCS = \
nsILDAPURL.idl \
nsILDAPErrors.idl \
nsILDAPServer.idl \
nsILDAPService.idl \
$(NULL)
ifdef MOZ_LDAP_XPCOM_EXPERIMENTAL

Просмотреть файл

@ -32,6 +32,7 @@ XPIDLSRCS= .\nsILDAPConnection.idl \
.\nsILDAPMessageListener.idl \
.\nsILDAPErrors.idl \
.\nsILDAPServer.idl \
.\nsILDAPService.idl \
!if defined(ENABLE_LDAP_EXPERIMENTAL)
!endif
$(NULL)

Просмотреть файл

@ -76,6 +76,13 @@ interface nsILDAPMessage : nsISupports
void getValues(in string attr, out unsigned long count,
[retval, array, size_is(count)] out string values);
/**
* The operation this message originated from
*
* @exception NS_ERROR_NULL_POINTER NULL pointer to getter
*/
readonly attribute nsILDAPOperation operation;
/**
* The result code (aka lderrno) for this message.
*

Просмотреть файл

@ -0,0 +1,180 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 the mozilla.org LDAP XPCOM component.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Leif Hedstrom <leif@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include "nsISupports.idl"
interface nsILDAPServer;
interface nsILDAPConnection;
interface nsILDAPMessageListener;
/**
* This interface provides an LDAP connection management service.
* It's used to cache already established LDAP connections, as well
* as reaping unused connections after a certain time period. This
* is done completely asynchronously, using callback functions.
*/
[scriptable, uuid(f73cc6c1-2301-484b-94a5-8885bca106d1)]
interface nsILDAPService : nsISupports {
/**
* Add a (possibly) new LDAP server entry to the service. A
* server entry holds information about the host, port and
* other components of the LDAP URL, as well as information
* used for binding a connection to the LDAP server.
*
* An LDAP Server entry (nsILDAPServer) contains the URL,
* user credentials, and other information related to the actual
* server itself. It is used for connecting, binding, rebinding,
* setting timeouts and so forth.
*
* @param aServer an nsILDAPServer object
*
* @exception NS_ERROR_FAILURE the server has already been
* added to the service
* @exception NS_ERROR_NULL_POINTER NULL pointer
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
void addServer(in nsILDAPServer aServer);
/**
* Mark an LDAP server, in the Service, as a candidate for
* deletion. If there are still leases ("users") of this server,
* the operation fails.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE either the server doesn't
* exist, or there are still
* leases oustanding
*/
void deleteServer(in wstring aKey);
/**
* Get the nsILDAPServer object for the specified server entry
* in the service.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key
* @exception NS_ERROR_NULL_POINTER NULL pointer
*/
nsILDAPServer getServer(in wstring aKey);
/**
* Request a connection from the service, asynchronously. If there is
* one "cached" already, we will actually call the callback function
* before returning from this function. This might be considered a bug,
* but for now be aware of this (see Bugzilla bug #75989).
*
* Calling this method does not increment the leases on this connection,
* you'll have to use the getConnection() method to actually get the
* connection itself (presumably from the callback/listener object).
* The listener needs to implement nsILDAPMessageListener, providing
* the OnLDAPMessage() method.
*
* @param aKey unique key identifying the server entry
* @param aMessageListener the listener object, which we will call
* when the LDAP bind message is available
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key,
* or we were unable to get a
* connection properly to the server
* @exception NS_ERROR_NOT_AVAILABLE couldn't create connection thread
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_UNEXPECTED unknown or unexpected error...
*/
void requestConnection(in wstring aKey,
in nsILDAPMessageListener aListener);
/**
* This is the nsLDAPConnection object related to this server.
* This does increase the lease counter on the object, so you have
* to call the releaseConnection() method to return it. It is
* important that you do this in matching pairs, and that you do
* not keep any dangling references to an object around after you
* have called the releaseConnection() method.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key
* @exception NS_ERROR_NULL_POINTER NULL pointer
*/
nsILDAPConnection getConnection(in wstring aKey);
/**
* Release the lease on a (cached) LDAP connection, making it a
* potential candidate for disconnection. Note that this will not
* delete the actual LDAP server entry in the service, it's still
* registered and can be used in future calls to requestConnection().
*
* This API might be deprecated in the future, once we figure out how
* to use weak references to support our special needs for reference
* counting. For the time being, it is vital that you call this function
* when you're done with a Connection, and that you do not keep any
* copies of the Connection object lingering around.
*
* @param aKey unique key identifying the server entry
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
*/
void releaseConnection(in wstring aKey);
/**
* If we detect that a connection is broken (server disconnected us,
* or any other problem with the link), we need to try to reestablish
* the connection. This is very similar to requestConnection(),
* except you use this when detecting an error with a connection
* that is being cached.
*
* @param aKey unique key identifying the server entry
* @param aMessageListener the listener object, which we will call
* when the LDAP bind message is available
*
* @exception NS_ERROR_FAILURE there is no server registered
* in the service with this key,
* or we were unable to get a
* connection properly to the server
* @exception NS_ERROR_NOT_AVAILABLE couldn't create connection thread
* @exception NS_ERROR_OUT_OF_MEMORY ran out of memory
* @exception NS_ERROR_UNEXPECTED unknown or unexpected error...
*/
void reconnectConnection(in wstring aKey,
in nsILDAPMessageListener aListener);
};

Просмотреть файл

@ -52,6 +52,7 @@ CPPSRCS = \
nsLDAPOperation.cpp \
nsLDAPURL.cpp \
nsLDAPServer.cpp \
nsLDAPService.cpp \
$(NULL)
ifdef MOZ_LDAP_XPCOM_EXPERIMENTAL
@ -60,7 +61,6 @@ DEFINES += -DMOZ_LDAP_XPCOM_EXPERIMENTAL
CPPSRCS += \
nsLDAPProtocolHandler.cpp \
nsLDAPChannel.cpp \
nsLDAPService.cpp \
$(NULL)
REQUIRES += mimetype
@ -74,4 +74,3 @@ CSRCS = \
EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) -lldap40 -llber40
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -34,10 +34,10 @@ CPP_OBJS = .\$(OBJDIR)\nsLDAPURL.obj \
.\$(OBJDIR)\nsLDAPConnection.obj \
.\$(OBJDIR)\nsLDAPOperation.obj \
.\$(OBJDIR)\nsLDAPServer.obj \
.\$(OBJDIR)\nsLDAPService.obj \
!if defined(ENABLE_LDAP_EXPERIMENTAL)
.\$(OBJDIR)\nsLDAPProtocolHandler.obj \
.\$(OBJDIR)\nsLDAPChannel.obj \
.\$(OBJDIR)\nsLDAPService.obj \
!endif
$(NULL)

Просмотреть файл

@ -49,6 +49,8 @@ extern "C" int nsLDAPThreadFuncsInit(LDAP *aLDAP);
// constructor
//
nsLDAPConnection::nsLDAPConnection()
: mConnectionHandle(0),
mPendingOperations(0)
{
NS_INIT_ISUPPORTS();
}
@ -77,7 +79,6 @@ nsLDAPConnection::~nsLDAPConnection()
if (mPendingOperations) {
delete mPendingOperations;
}
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsLDAPConnection, nsILDAPConnection,
@ -573,6 +574,11 @@ nsLDAPConnection::InvokeMessageCallback(LDAPMessage *aMsgHandle,
operation = getter_AddRefs(NS_STATIC_CAST(nsILDAPOperation *, data));
// 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)
//

Просмотреть файл

@ -57,7 +57,6 @@ nsLDAPMessage::nsLDAPMessage()
//
nsLDAPMessage::~nsLDAPMessage(void)
{
if (mMsgHandle) {
int rc = ldap_msgfree(mMsgHandle);
@ -527,6 +526,18 @@ nsLDAPMessage::GetValues(const char *aAttr, PRUint32 *aCount,
return NS_OK;
}
// readonly attribute nsILDAPOperation operation;
NS_IMETHODIMP nsLDAPMessage::GetOperation(nsILDAPOperation **_retval)
{
if (!_retval) {
NS_ERROR("nsLDAPMessage::GetOperation: null pointer ");
return NS_ERROR_NULL_POINTER;
}
NS_IF_ADDREF(*_retval = mOperation);
return NS_OK;
}
NS_IMETHODIMP
nsLDAPMessage::ToUnicode(PRUnichar* *aString)
{

Просмотреть файл

@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s): Dan Mosedale <dmose@mozilla.org>
* Leif Hedstrom <leif@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
@ -38,11 +39,11 @@
#include "nsLDAPOperation.h"
#include "nsLDAPMessage.h"
#include "nsLDAPServer.h"
#include "nsLDAPService.h"
#ifdef MOZ_LDAP_XPCOM_EXPERIMENTAL
#include "nsLDAPProtocolHandler.h"
#include "nsLDAPChannel.h"
#include "nsLDAPService.h"
#endif
// use the default constructor
@ -52,10 +53,10 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPOperation);
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPMessage);
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPURL);
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPServer);
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsLDAPService, Init);
#ifdef MOZ_LDAP_XPCOM_EXPERIMENTAL
NS_GENERIC_FACTORY_CONSTRUCTOR(nsLDAPProtocolHandler);
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsLDAPService, Init);
#endif
@ -73,12 +74,12 @@ static nsModuleComponentInfo components[] =
"@mozilla.org/network/ldap-message;1", nsLDAPMessageConstructor },
{ "LDAP Server", NS_LDAPSERVER_CID,
"@mozilla.org/network/ldap-server;1", nsLDAPServerConstructor },
{ "LDAP Service", NS_LDAPSERVICE_CID,
"@mozilla.org/network/ldap-service;1", nsLDAPServiceConstructor },
#ifdef MOZ_LDAP_XPCOM_EXPERIMENTAL
{ "LDAP Protocol Handler", NS_LDAPPROTOCOLHANDLER_CID,
NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ldap",
nsLDAPProtocolHandlerConstructor },
{ "LDAP Service", NS_LDAPSERVICE_CID,
"@mozilla.org/network/ldap-service;1", nsLDAPServiceConstructor },
#endif
{ "LDAP URL", NS_LDAPURL_CID,
"@mozilla.org/network/ldap-url;1", nsLDAPURLConstructor }

Просмотреть файл

@ -17,7 +17,7 @@
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Dan Mosedale <dmose@mozilla.org>
* Contributor(s): Leif Hedstrom <leif@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
@ -34,10 +34,206 @@
#include "nsLDAPInternal.h"
#include "nsLDAPService.h"
#include "nsLDAPConnection.h"
#include "nsLDAPOperation.h"
#include "nsXPIDLString.h"
#include "nsIServiceManager.h"
#include "nsIConsoleService.h"
#include "nsILDAPURL.h"
#include "nsAutoLock.h"
// Constants for CIDs used here.
//
static NS_DEFINE_CID(kLDAPConnectionCID, NS_LDAPCONNECTION_CID);
static NS_DEFINE_CID(kLDAPOperationCID, NS_LDAPOPERATION_CID);
// First we provide all the methods for the "local" class
// nsLDAPServiceEntry.
//
// constructor
//
nsLDAPServiceEntry::nsLDAPServiceEntry()
: mLeases(0),
mDelete(PR_FALSE),
mRebinding(PR_FALSE)
{
mTimestamp = LL_Zero();
}
// destructor
//
nsLDAPServiceEntry::~nsLDAPServiceEntry()
{
}
// Init function
//
PRBool nsLDAPServiceEntry::Init()
{
nsresult rv;
rv = NS_NewISupportsArray(getter_AddRefs(mListeners));
if (NS_FAILED(rv)) {
return PR_FALSE;
}
return PR_TRUE;
}
// Set/Get the timestamp when this server was last used. We might have
// to use an "interval" here instead, see Bug #76887.
//
PRTime nsLDAPServiceEntry::GetTimestamp()
{
return mTimestamp;
}
void nsLDAPServiceEntry::SetTimestamp()
{
mTimestamp = PR_Now();
}
// Increment, decrement and Get the leases. This code might go away
// with bug #75954.
//
void nsLDAPServiceEntry::IncrementLeases()
{
mLeases++;
}
PRBool nsLDAPServiceEntry::DecrementLeases()
{
if (!mLeases) {
return PR_FALSE;
}
mLeases--;
return PR_TRUE;
}
PRUint32 nsLDAPServiceEntry::GetLeases()
{
return mLeases;
}
// Get/Set the nsLDAPServer object for this entry.
//
nsILDAPServer *nsLDAPServiceEntry::GetServer()
{
nsILDAPServer *server;
NS_IF_ADDREF(server = mServer);
return server;
}
PRBool nsLDAPServiceEntry::SetServer(nsILDAPServer *aServer)
{
if (!aServer) {
return PR_FALSE;
}
mServer = aServer;
return PR_TRUE;
}
// Get/Set/Clear the nsLDAPConnection object for this entry.
//
nsILDAPConnection *nsLDAPServiceEntry::GetConnection()
{
nsILDAPConnection *conn;
NS_IF_ADDREF(conn = mConnection);
return conn;
}
void nsLDAPServiceEntry::SetConnection(nsILDAPConnection *aConnection)
{
mConnection = aConnection;
}
// Get/Set the nsLDAPMessage object for this entry (it's a "cache").
//
nsILDAPMessage *nsLDAPServiceEntry::GetMessage()
{
nsILDAPMessage *message;
NS_IF_ADDREF(message = mMessage);
return message;
}
void nsLDAPServiceEntry::SetMessage(nsILDAPMessage *aMessage)
{
mMessage = aMessage;
}
// Push/Pop pending listeners/callback for this server entry. This is
// implemented as a "stack" on top of the nsVoidArrays, since we can
// potentially have more than one listener waiting for the connection
// to be avilable for consumption.
//
nsILDAPMessageListener *nsLDAPServiceEntry::PopListener()
{
nsILDAPMessageListener *listener;
PRUint32 count;
mListeners->Count(&count);
if (!count) {
return 0;
}
listener = NS_STATIC_CAST(nsILDAPMessageListener *,
mListeners->ElementAt(0));
mListeners->RemoveElementAt(0);
return listener;
}
PRBool nsLDAPServiceEntry::PushListener(nsILDAPMessageListener *listener)
{
PRBool ret;
PRUint32 count;
mListeners->Count(&count);
ret = mListeners->InsertElementAt(listener, count);
return ret;
}
// Mark this server to currently be rebinding. This is to avoid a
// race condition where multiple consumers could potentially request
// to reconnect the connection.
//
PRBool nsLDAPServiceEntry::IsRebinding()
{
return mRebinding;
}
void nsLDAPServiceEntry::SetRebinding(PRBool aState)
{
mRebinding = aState;
}
// Mark a service entry for deletion, this is "dead" code right now,
// see bug #75966.
//
PRBool nsLDAPServiceEntry::DeleteEntry()
{
mDelete = PR_TRUE;
return PR_TRUE;
}
// This is the end of the nsLDAPServiceEntry class
// Here begins the implementation for nsLDAPService
//
NS_IMPL_THREADSAFE_ISUPPORTS2(nsLDAPService,
nsILDAPService,
nsILDAPMessageListener);
// constructor
//
nsLDAPService::nsLDAPService()
: mLock(0),
mServers(0),
mConnections(0)
{
NS_INIT_ISUPPORTS();
}
@ -46,40 +242,610 @@ nsLDAPService::nsLDAPService()
//
nsLDAPService::~nsLDAPService()
{
// Delete the hash table holding the entries
if (mServers) {
delete mServers;
}
// Delete the hash holding the "reverse" lookups from conn to server
if (mConnections) {
delete mConnections;
}
// Delete the lock object
if (mLock) {
PR_DestroyLock(mLock);
}
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsLDAPService,nsIRunnable);
// initialize; should only be called by the generic constructor after
// creation. This is where the thread gets spun up.
// Initializer, create some internal hash tables etc.
//
NS_IMETHODIMP
nsLDAPService::Init(void)
nsresult nsLDAPService::Init()
{
nsresult rv;
if (!mLock) {
mLock = PR_NewLock();
if (!mLock) {
NS_ERROR("nsLDAPService::Init: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
}
NS_ASSERTION(!mThread, "nsLDAPService already initialized!");
if (!mServers) {
mServers = new nsHashtable(16, PR_FALSE);
if (!mServers) {
NS_ERROR("nsLDAPService::Init: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
}
rv = NS_NewThread(getter_AddRefs(mThread),
this, 0, PR_JOINABLE_THREAD);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// for nsIRunnable. all the processing work happens here.
//
NS_IMETHODIMP
nsLDAPService::Run(void)
{
PR_LOG(gLDAPLogModule, PR_LOG_DEBUG, ("nsLDAPService::Run() entered\n"));
// XXX - should use mThreadRunning here
//
while (1) {
if (!mConnections) {
mConnections = new nsHashtable(16, PR_FALSE);
if (!mConnections) {
NS_ERROR("nsLDAPService::Init: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
}
return NS_OK;
}
// void addServer (in nsILDAPServer aServer);
NS_IMETHODIMP nsLDAPService::AddServer(nsILDAPServer *aServer)
{
nsLDAPServiceEntry *entry;
nsXPIDLString key;
nsresult rv;
if (!aServer) {
NS_ERROR("nsLDAPService::AddServer: null pointer ");
return NS_ERROR_NULL_POINTER;
}
// Set up the hash key for the server entry
//
rv = aServer->GetKey(getter_Copies(key));
if (NS_FAILED(rv)) {
switch (rv) {
// Only pass along errors we are aware of
//
case NS_ERROR_OUT_OF_MEMORY:
case NS_ERROR_NULL_POINTER:
return rv;
default:
return NS_ERROR_FAILURE;
}
}
// Create the new service server entry, and add it into the hash table
//
entry = new nsLDAPServiceEntry;
if (!entry) {
NS_ERROR("nsLDAPService::AddServer: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
if (!entry->Init()) {
delete entry;
NS_ERROR("nsLDAPService::AddServer: out of memory ");
return NS_ERROR_OUT_OF_MEMORY;
}
if (!entry->SetServer(aServer)) {
delete entry;
return NS_ERROR_FAILURE;
}
// We increment the refcount here for the server entry, when
// we purge a server completely from the service (TBD), we
// need to decrement the counter as well.
//
{
nsStringKey hashKey(key);
nsAutoLock lock(mLock);
if (mServers->Exists(&hashKey)) {
// Collision detected, lets just throw away this service entry
// and keep the old one.
//
delete entry;
return NS_ERROR_FAILURE;
}
mServers->Put(&hashKey, entry);
}
NS_ADDREF(aServer);
return NS_OK;
}
// void deleteServer (in wstring aKey);
NS_IMETHODIMP nsLDAPService::DeleteServer(const PRUnichar *aKey)
{
nsLDAPServiceEntry *entry;
nsStringKey hashKey(aKey, -1, nsStringKey::NEVER_OWN);
nsAutoLock lock(mLock);
// We should probably rename the key for this entry now that it's
// "deleted", so that we can add in a new one with the same ID.
// This is bug #77669.
//
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (entry) {
if (entry->GetLeases() > 0) {
return NS_ERROR_FAILURE;
}
entry->DeleteEntry();
} else {
// There is no Server entry for this key
//
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// nsILDAPServer getServer (in wstring aKey);
NS_IMETHODIMP nsLDAPService::GetServer(const PRUnichar *aKey,
nsILDAPServer **_retval)
{
nsLDAPServiceEntry *entry;
nsStringKey hashKey(aKey, -1, nsStringKey::NEVER_OWN);
nsAutoLock lock(mLock);
if (!_retval) {
NS_ERROR("nsLDAPService::GetServer: null pointer ");
return NS_ERROR_NULL_POINTER;
}
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (!entry) {
*_retval = 0;
return NS_ERROR_FAILURE;
}
if (!(*_retval = entry->GetServer())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
//void requestConnection (in wstring aKey,
// in nsILDAPMessageListener aMessageListener);
NS_IMETHODIMP nsLDAPService::RequestConnection(const PRUnichar *aKey,
nsILDAPMessageListener *aListener)
{
nsLDAPServiceEntry *entry;
nsCOMPtr<nsILDAPConnection> conn;
nsCOMPtr<nsILDAPMessage> message;
nsresult rv;
nsStringKey hashKey(aKey, -1, nsStringKey::NEVER_OWN);
if (!aListener) {
NS_ERROR("nsLDAPService::RequestConection: null pointer ");
return NS_ERROR_NULL_POINTER;
}
// Try to find a possibly cached connection and LDAP message.
//
{
nsAutoLock lock(mLock);
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (!entry) {
return NS_ERROR_FAILURE;
}
entry->SetTimestamp();
conn = getter_AddRefs(entry->GetConnection());
message = getter_AddRefs(entry->GetMessage());
}
if (conn) {
if (message) {
// We already have the connection, and the message, ready to
// be used. This might be confusing, since we actually call
// the listener before this function returns, see bug #75899.
//
aListener->OnLDAPMessage(message);
return NS_OK;
}
} else {
rv = EstablishConnection(entry, aListener);
if (NS_FAILED(rv)) {
return rv;
}
}
// We got a new connection, now push the listeners on our stack,
// until we get the LDAP message back.
//
{
nsAutoLock lock(mLock);
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (!entry ||
!entry->PushListener(NS_STATIC_CAST(nsILDAPMessageListener *,
aListener))) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
// nsILDAPConnection getConnection (in wstring aKey);
NS_IMETHODIMP nsLDAPService::GetConnection(const PRUnichar *aKey,
nsILDAPConnection **_retval)
{
nsLDAPServiceEntry *entry;
nsStringKey hashKey(aKey, -1, nsStringKey::NEVER_OWN);
nsAutoLock lock(mLock);
if (!_retval) {
NS_ERROR("nsLDAPService::GetConnection: null pointer ");
return NS_ERROR_NULL_POINTER;
}
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (!entry) {
*_retval = 0;
return NS_ERROR_FAILURE;
}
entry->SetTimestamp();
entry->IncrementLeases();
if (!(*_retval = entry->GetConnection())){
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// void releaseConnection (in wstring aKey);
NS_IMETHODIMP nsLDAPService::ReleaseConnection(const PRUnichar *aKey)
{
nsLDAPServiceEntry *entry;
nsStringKey hashKey(aKey, -1, nsStringKey::NEVER_OWN);
nsAutoLock lock(mLock);
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (!entry) {
return NS_ERROR_FAILURE;
}
if (entry->GetLeases() > 0) {
entry->SetTimestamp();
entry->DecrementLeases();
} else {
// Releasing a non-leased connection is currently a No-Op.
//
}
return NS_OK;
}
// void reconnectConnection (in wstring aKey,
// in nsILDAPMessageListener aMessageListener);
NS_IMETHODIMP nsLDAPService::ReconnectConnection(const PRUnichar *aKey,
nsILDAPMessageListener *aListener)
{
nsLDAPServiceEntry *entry;
nsresult rv;
nsStringKey hashKey(aKey, -1, nsStringKey::NEVER_OWN);
if (!aListener) {
NS_ERROR("nsLDAPService::ReconnectConnection: null pointer ");
return NS_ERROR_NULL_POINTER;
}
{
nsAutoLock lock(mLock);
entry = NS_STATIC_CAST(nsLDAPServiceEntry *, mServers->Get(&hashKey));
if (!entry) {
return NS_ERROR_FAILURE;
}
entry->SetTimestamp();
if (entry->IsRebinding()) {
if (!entry->PushListener(aListener)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// Clear the old connection and message, which should get garbaged
// collected now. We mark this as being "rebinding" now, and it
// we be marked as finished either if there's an error condition,
// or if the OnLDAPMessage() method gets called (i.e. bind() done).
//
entry->SetMessage(0);
entry->SetConnection(0);
// Get a new connection
//
entry->SetRebinding(PR_TRUE);
}
rv = EstablishConnection(entry, aListener);
if (NS_FAILED(rv)) {
return rv;
}
{
nsAutoLock lock(mLock);
if (!entry->PushListener(NS_STATIC_CAST(nsILDAPMessageListener *,
aListener))) {
entry->SetRebinding(PR_FALSE);
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
/**
* Messages received are passed back via this function.
*
* @arg aMessage The message that was returned, 0 if none was.
*
* void OnLDAPMessage (in nsILDAPMessage aMessage)
*/
NS_IMETHODIMP
nsLDAPService::OnLDAPMessage(nsILDAPMessage *aMessage)
{
nsCOMPtr<nsILDAPOperation> operation;
nsCOMPtr<nsILDAPConnection> connection;
PRInt32 messageType;
// XXXleif: NULL messages are supposedly allowed, but the semantics
// are not definted (yet?). This is something to look out for...
//
// figure out what sort of message was returned
//
nsresult rv = aMessage->GetType(&messageType);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::OnLDAPMessage(): unexpected error in "
"nsLDAPMessage::GetType()");
return NS_ERROR_UNEXPECTED;
}
switch (messageType) {
case LDAP_RES_BIND:
// a bind has completed
//
rv = aMessage->GetOperation(getter_AddRefs(operation));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::OnLDAPMessage(): unexpected error in "
"nsLDAPMessage::GetOperation()");
return NS_ERROR_UNEXPECTED;
}
rv = operation->GetConnection(getter_AddRefs(connection));
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::OnLDAPMessage(): unexpected error in "
"nsLDAPOperation::GetConnection()");
return NS_ERROR_UNEXPECTED;
}
// Now we have the connection, lets find the corresponding
// server entry in the Service.
//
{
nsCOMPtr<nsILDAPMessageListener> listener;
nsCOMPtr<nsILDAPMessage> message;
nsLDAPServiceEntry *entry;
nsVoidKey connKey(NS_STATIC_CAST(nsILDAPConnection *,
connection));
nsAutoLock lock(mLock);
entry = NS_STATIC_CAST(nsLDAPServiceEntry *,
mConnections->Get(&connKey));
if (!entry) {
return NS_ERROR_FAILURE;
}
message = getter_AddRefs(entry->GetMessage());
if (message) {
// We already have a message, lets keep that one.
//
return NS_ERROR_FAILURE;
}
entry->SetRebinding(PR_FALSE);
entry->SetMessage(aMessage);
// Now process all the pending callbacks/listeners. We
// have to make sure to unlock before calling a listener,
// since it's likely to call back into us again.
//
while (listener = entry->PopListener()) {
lock.unlock();
listener->OnLDAPMessage(aMessage);
lock.lock();
}
}
break;
default:
NS_WARNING("nsLDAPService::OnLDAPMessage(): unexpected LDAP message "
"received");
// get the console service so we can log a message
//
nsCOMPtr<nsIConsoleService> consoleSvc =
do_GetService("@mozilla.org/consoleservice;1", &rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPChannel::OnLDAPMessage() couldn't get console "
"service");
break;
}
// log the message
//
rv = consoleSvc->LogStringMessage(
NS_LITERAL_STRING("LDAP: WARNING: nsLDAPService::OnLDAPMessage(): Unexpected LDAP message received").get());
NS_ASSERTION(NS_SUCCEEDED(rv), "nsLDAPService::OnLDAPMessage(): "
"consoleSvc->LogStringMessage() failed");
break;
}
return NS_OK;
}
// Helper function to establish an LDAP connection properly.
//
nsresult nsLDAPService::EstablishConnection(nsLDAPServiceEntry *aEntry,
nsILDAPMessageListener *aListener)
{
nsCOMPtr<nsILDAPOperation> operation;
nsCOMPtr<nsILDAPServer> server;
nsCOMPtr<nsILDAPURL> url;
nsCOMPtr<nsILDAPConnection> conn, conn2;
nsCOMPtr<nsILDAPMessage> message;
nsXPIDLCString host;
nsXPIDLString binddn;
nsXPIDLString password;
PRInt32 port;
nsresult rv;
server = getter_AddRefs(aEntry->GetServer());
if (!server) {
return NS_ERROR_FAILURE;
}
// Get username and password from the server entry.
//
rv = server->GetBinddn(getter_Copies(binddn));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = server->GetPassword(getter_Copies(password));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Get the host and port out of the URL, which is in the server entry.
//
rv = server->GetUrl(getter_AddRefs(url));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = url->GetHost(getter_Copies(host));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = url->GetPort(&port);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Create a new connection for this server.
//
conn = do_CreateInstance(kLDAPConnectionCID, &rv);
if (NS_FAILED(rv)) {
NS_ERROR("nsLDAPService::EstablishConnection(): could not create "
"@mozilla.org/network/ldap-connection;1");
return NS_ERROR_FAILURE;
}
// Here we need to provide the binddn, see bug #75990
//
rv = conn->Init(host, port, 0);
if (NS_FAILED(rv)) {
switch (rv) {
// Only pass along errors we are aware of
//
case NS_ERROR_OUT_OF_MEMORY:
case NS_ERROR_NOT_AVAILABLE:
case NS_ERROR_FAILURE:
return rv;
case NS_ERROR_ILLEGAL_VALUE:
default:
return NS_ERROR_UNEXPECTED;
}
}
// Try to detect a collision, i.e. someone established a connection
// just before we did. If so, we drop ours. This code is somewhat
// similar to what happens in RequestConnection(), i.e. we try to
// call the listener directly if possible, and if not, push it on
// the stack of pending requests.
//
{
nsAutoLock lock(mLock);
conn2 = getter_AddRefs(aEntry->GetConnection());
message = getter_AddRefs(aEntry->GetMessage());
}
if (conn2) {
// Drop the new connection, we can't use it.
//
conn = 0;
if (message) {
aListener->OnLDAPMessage(message);
return NS_OK;
}
{
nsAutoLock lock(mLock);
if (!aEntry->PushListener(NS_STATIC_CAST(nsILDAPMessageListener *,
aListener))) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
// We made the connection, lets store it to the server entry,
// and also update the reverse lookup tables (for finding the
// server entry related to a particular connection).
//
{
nsVoidKey connKey(NS_STATIC_CAST(nsILDAPConnection *, conn));
nsAutoLock lock(mLock);
aEntry->SetConnection(conn);
mConnections->Put(&connKey, aEntry);
}
// Setup the bind() operation.
//
operation = do_CreateInstance(kLDAPOperationCID, &rv);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
rv = operation->Init(conn, this);
if (NS_FAILED(rv)) {
return NS_ERROR_UNEXPECTED; // this should never happen
}
// Start a bind operation
//
// Here we need to support the password, see bug #75990
//
rv = operation->SimpleBind(0);
if (NS_FAILED(rv)) {
switch (rv) {
// Only pass along errors we are aware of
//
case NS_ERROR_LDAP_ENCODING_ERROR:
case NS_ERROR_FAILURE:
case NS_ERROR_OUT_OF_MEMORY:
return rv;
default:
return NS_ERROR_UNEXPECTED;
}
}
return NS_OK;
}

Просмотреть файл

@ -17,7 +17,7 @@
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): Dan Mosedale <dmose@mozilla.org>
* Contributor(s): Leif Hedstrom <leif@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
@ -32,12 +32,19 @@
* GPL.
*/
#ifndef nsLDAPService_h___
#define nsLDAPService_h___
#include "nsIRunnable.h"
#include "nsLDAP.h"
#include "ldap.h"
#include "nsString.h"
#include "nsSupportsArray.h"
#include "nsHashtable.h"
#include "nsILDAPService.h"
#include "nsILDAPMessage.h"
#include "nsILDAPMessageListener.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsILDAPServer.h"
#include "nsILDAPConnection.h"
#include "nsILDAPMessage.h"
// 6a89ae33-7a90-430d-888c-0dede53a951a
//
@ -47,28 +54,78 @@
{0x88, 0x8c, 0x0d, 0xed, 0xe5, 0x3a, 0x95, 0x1a} \
}
class nsLDAPService : public nsIRunnable
// This is a little "helper" class, we use to store information
// related to one Service entry (one LDAP server).
//
class nsLDAPServiceEntry
{
public:
nsLDAPServiceEntry();
virtual ~nsLDAPServiceEntry();
PRBool Init();
inline PRUint32 GetLeases();
inline void IncrementLeases();
inline PRBool DecrementLeases();
inline PRTime GetTimestamp();
inline void SetTimestamp();
inline nsILDAPServer *GetServer();
inline PRBool SetServer(nsILDAPServer *aServer);
inline nsILDAPConnection *GetConnection();
inline void SetConnection(nsILDAPConnection *aConnection);
inline nsILDAPMessage *GetMessage();
inline void SetMessage(nsILDAPMessage *aMessage);
inline nsILDAPMessageListener *PopListener();
inline PRBool PushListener(nsILDAPMessageListener *);
inline PRBool IsRebinding();
inline void SetRebinding(PRBool);
inline PRBool DeleteEntry();
protected:
PRUint32 mLeases; // The number of leases currently granted
PRTime mTimestamp; // Last time this server was "used"
PRBool mDelete; // This entry is due for deletion
PRBool mRebinding; // Keep state if we are rebinding or not
nsCOMPtr<nsILDAPServer> mServer;
nsCOMPtr<nsILDAPConnection> mConnection;
nsCOMPtr<nsILDAPMessage> mMessage;
// Array holding all the pending callbacks (listeners) for this entry
nsCOMPtr<nsISupportsArray> mListeners;
};
// This is the interface we're implementing.
//
class nsLDAPService : public nsILDAPService, public nsILDAPMessageListener
{
public:
// interface decls
//
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSILDAPSERVICE
NS_DECL_NSILDAPMESSAGELISTENER
// constructor and destructor
//
nsLDAPService();
virtual ~nsLDAPService();
// initialize; should only be called by the generic
// constructor after creation
//
NS_METHOD Init(void);
nsresult Init();
protected:
nsCOMPtr<nsIThread> mThread;
PRBool mThreadRunning;
nsresult EstablishConnection(nsLDAPServiceEntry *,
nsILDAPMessageListener *);
PRLock *mLock; // Lock mechanism
nsHashtable *mServers; // Hash table holding server entries
nsHashtable *mConnections; // Hash table holding "reverse"
// lookups from connection to server
};
#endif // nsLDAPService_h___

Двоичные данные
directory/xpcom/macbuild/mozldap.mcp

Двоичный файл не отображается.

Двоичные данные
directory/xpcom/macbuild/mozldapIDL.mcp

Двоичный файл не отображается.