Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3299 lines
107 KiB

/*++
Microsoft Windows NT RPC Name Service
Copyright (C) Microsoft Corporation, 1995 - 1999
Module Name:
objects.hxx
Abstract:
This file contains the definitions of all basic classes used in the server,
excluding the data structure classes and classes used for network interactions.
Author:
Satish Thatte (SatishT) 08/21/95 Created all the code below except where
otherwise indicated.
--*/
/* For every operation with a dynamic object, memory
management should be a part of the description and
specification for every parameter. Fix that along
with other documentation.
*/
#ifndef _OBJECTS_HXX_
#define _OBJECTS_HXX_
class CGUID;
class CInterface;
struct CBVWrapper;
class CServerEntry;
class CNonLocalServerEntry;
class CFullServerEntry;
class CInterfaceIndex;
struct CMailSlotReplyItem;
class CServerLookupHandle;
class CServerObjectInqHandle;
typedef TIIterator<CGUID> TGuidIterator;
// The following enumeration is the the type of entry the object is.
enum EntryType {
ServerEntryType,
GroupEntryType,
ProfileEntryType,
NonLocalServerEntryType,
FullServerEntryType,
MemberEntryType,
AnyEntryType
};
/*++
Class Definition:
CUnsigned32
Abstract:
This is the unsigned number wrapper class.
--*/
class CUnsigned32 : public IOrderedItem {
protected:
DWORD dwVal;
public:
CUnsigned32() {
dwVal = 0;
}
CUnsigned32( const DWORD dw ) {
dwVal = dw;
}
operator DWORD() { return dwVal; }
virtual int compare( const IOrderedItem& O ) {
const CUnsigned32& arg = (CUnsigned32&) O;
return dwVal > arg.dwVal ? 1 : (dwVal == arg.dwVal ? 0 : -1);
}
};
/*++
Class Definition:
CStringW
Abstract:
This is the unicode string wrapper class.
Note that string comparison is case insensitive.
--*/
class CStringW : public IOrderedItem {
protected:
STRING_T pszVal;
public:
int length() { return wcslen(pszVal); }
int isEmptyString() {
return (pszVal == NULL) || (_wcsicmp(pszVal,TEXT("")) == 0);
}
static STRING_T copyString(
CONST_STRING_T str
)
{
STRING_T result = new WCHAR [(wcslen(str)+1)*sizeof(WCHAR)];
wcscpy(result,str);
return result;
}
static STRING_T copyMIDLstring( // for use in out RPC parameters
// which are deallocated by stubs
CONST_STRING_T str
)
{
STRING_T result = (STRING_T) midl_user_allocate((wcslen(str)+1)*sizeof(WCHAR));
wcscpy(result,str);
return result;
}
STRING_T copyAsString() {
return copyString(pszVal);
}
STRING_T copyAsMIDLstring() { // for use in out RPC parameters
// which are deallocated by stubs
return copyMIDLstring(pszVal);
}
CStringW() {
pszVal = NULL;
}
CStringW( CONST_STRING_T p ) {
pszVal = copyString(p);
}
CStringW& operator=( const CStringW& str ) {
delete [] pszVal;
pszVal = copyString(str.pszVal);
return *this;
}
CStringW( const CStringW& str ) {
pszVal = copyString(str.pszVal);
}
virtual ~CStringW() // base class destructor should be virtual
{
delete [] pszVal;
}
operator STRING_T() { return pszVal; }
virtual int compare( const IOrderedItem& O ) {
const CStringW& S = (CStringW&) O;
return _wcsicmp(pszVal,S.pszVal);
}
};
typedef TCGuardedSkipList<CStringW> TGSLString;
typedef TCGuardedSkipListIterator<CStringW> TGSLStringIter;
typedef TCSafeSkipList<CStringW> TSSLString;
typedef TCSafeSkipListIterator<CStringW> TSSLStringIter;
typedef TCSafeLinkList<CStringW> TSLLString;
typedef TCSafeLinkListIterator<CStringW> TSLLStringIter;
/*++
Class Definition:
CGUID
Abstract:
This is the GUID wrapper class.
--*/
class CGUID : public IOrderedItem {
GUID rep;
public:
CGUID() {
memset(&rep,0,sizeof(rep));
}
CGUID( const GUID& g ) : rep(g) {}
virtual int compare(const IOrderedItem& C ) {
CGUID& S = (CGUID&) C;
return memcmp(&rep, &(S.rep),sizeof(rep));
}
GUID myGUID() { return rep; }
BOOL IsNil() {
RPC_STATUS dummyStatus;
return UuidIsNil(&rep,&dummyStatus);
}
CStringW* ConvertToString();
};
typedef TCSafeSkipListIterator<CGUID> TSSLGuidIterator;
/*++
Class Definition:
CGUIDVersion
Abstract:
This is the RPC_SYNTAX_IDENTIFIER wrapper class.
--*/
class CGUIDVersion : public IOrderedItem {
protected:
struct CidAndVersion { // this is just a readability aid for
// the implementation of isCompatibleGV
CGUID id;
unsigned short major;
unsigned short minor;
CidAndVersion (const RPC_SYNTAX_IDENTIFIER& in) : id(in.SyntaxGUID) {
major = in.SyntaxVersion.MajorVersion;
minor = in.SyntaxVersion.MinorVersion;
}
CidAndVersion() {
memset(&id,0,sizeof(GUID));
major = minor = 0;
}
};
RPC_SYNTAX_IDENTIFIER idAndVersion;
public:
CGUIDVersion( const RPC_SYNTAX_IDENTIFIER& g ) {
idAndVersion = g;
}
CGUIDVersion() {memset(&idAndVersion, 0, sizeof(idAndVersion));} // NULL case
RPC_SYNTAX_IDENTIFIER myIdAndVersion() { return idAndVersion; }
operator RPC_SYNTAX_IDENTIFIER() { return idAndVersion; }
GUID myGUID() { return idAndVersion.SyntaxGUID; }
virtual int compare(const IOrderedItem& C ) {
const CGUIDVersion& S = (CGUIDVersion&) C;
return memcmp(&idAndVersion, &S.idAndVersion, sizeof(RPC_SYNTAX_IDENTIFIER));
}
int isMatching(const CGUIDVersion& other, UNSIGNED32 vers_option);
int isCompatibleGV(const CGUIDVersion& other) {
return isMatching(other,RPC_C_VERS_COMPATIBLE);
}
};
/*++
Class Definition:
CMailSlotReplyItem
Abstract:
This is the class of items to be marshalled into mailslot reply buffers.
The class, and especially the marshalling code, is dictated largely by
compatibility requirements for the old locator.
Everything in a CMailSlotReplyItem object is borrowed from some
other object and is therefore not freed upon destruction.
The primary operation is "marshall".
--*/
struct CMailSlotReplyItem : public IDataItem {
/* these are the items needed to marshall a reply packet */
RPC_SYNTAX_IDENTIFIER Interface;
RPC_SYNTAX_IDENTIFIER XferSyntax;
STRING_T binding;
STRING_T entryName;
TCSafeSkipList<CGUID> *pObjectList;
/* the marshall operation returns the number of bytes written to the buffer */
DWORD Marshall(char * pcBuffer, long lBufferSize);
};
typedef TIIterator<CMailSlotReplyItem> TMSRIIterator;
typedef TCSafeLinkList<CMailSlotReplyItem> TMSRILinkList;
typedef TCSafeLinkListIterator<CMailSlotReplyItem> TMSRILinkListIterator;
/*++
Class Definition:
CBVWrapper
Abstract:
This is a very thin wrapper for NSI_BINDING_VECTOR_T to make the
latter usable with linked lists (by inheriting from IDataItem).
--*/
struct CBVWrapper : public IDataItem {
NSI_BINDING_VECTOR_T *pBVT;
CBVWrapper(NSI_BINDING_VECTOR_T *p) {
pBVT = p;
}
void rundown();
};
typedef TIIterator<CBVWrapper> TBVIterator;
typedef TCSafeLinkList<CBVWrapper> TBVSafeLinkList;
typedef TCSafeLinkListIterator<CBVWrapper> TBVSafeLinkListIterator;
/*++
Class Definition:
CNSBinding
Abstract:
A thin wrapper for NSI_BINDING_T. Note that the strings in a NSI_BINDING_T used
to initialize a CNSBinding object are not copied, only the pointers are copied.
--*/
class CNSBinding : public CStringW
{
NSI_BINDING_T rep;
public:
CNSBinding( // this is a little crude, but hey..
NSI_BINDING_T& binding
) : rep(binding)
{
pszVal = catenate(
binding.string,
binding.entry_name
);
}
operator NSI_BINDING_T()
{
return rep;
}
void
copyBinding(NSI_BINDING_T& result)
{
result.string = CStringW::copyMIDLstring(rep.string);
result.entry_name = CStringW::copyMIDLstring(rep.entry_name);
result.entry_name_syntax = rep.entry_name_syntax;
}
};
/*++
Class Definition:
CBindingVector
Abstract:
Used mainly to keep vectors of binding handles. Iterators returning
vectors of handles is what most NS handles are in essence.
--*/
class CBindingVector : public TCSafeSkipList<CStringW>
{
CServerEntry *pMyEntry; // the entry this belongs to
public:
CBindingVector(NSI_SERVER_BINDING_VECTOR_T*, CServerEntry*);
CBindingVector(CServerEntry *pEntry)
: pMyEntry(pEntry)
{
}
~CBindingVector() { // must destroy binding strings stored here
wipeOut();
}
int merge(NSI_SERVER_BINDING_VECTOR_T* pHandles);
TBVSafeLinkList * formObjBVT(
TSLLString * pLLobjectStrings,
long ulVS // max BV size
);
SkipStatus insertBindingHandle(STRING_T bindingHandle) {
CStringW *pTemp = new CStringW(bindingHandle);
return insert(pTemp);
}
// so that this can be marshalled when a reply has to
// be sent to broadcast requests.
TMSRILinkList *msriList(
CInterface *pIf,
TCSafeSkipList<CGUID>* psslObjList
);
// remove from the binding vector the bindings that
// are common to another binding vector. this is used
// again for backward compatibility to remove common
// binding vector from old locator.
// returns false if the binding vector is emptied.
// this function assumes that these are called for
// the same entry names.
BOOL purgeCommonEntries(CBindingVector *src)
{
ULONG sz, i;
CStringW *pBinding1, *pBinding2;
TCSafeSkipListIterator<CStringW> pBindingIterator(*this);
sz = size();
for (i = 0; i < sz; i++)
{
pBinding1 = pBindingIterator.next();
pBinding2 = src->find(pBinding1);
if (pBinding2)
remove(pBinding2);
}
if (size())
return FALSE;
else
return TRUE;
}
};
/*++
Class Definition:
CInterface
Abstract:
An interface and its vector of binding handles.
The interface can be searched for, using the GUIDVersion
comparison operator.
The major caveat is that we essentially ignore transfer syntax.
According to DCE, there should be a separate entry for each
interface/transfer syntax combination. We assume that NDR is
always used.
--*/
class CInterface : public CGUIDVersion {
friend class CServerEntry;
private:
CServerEntry * m_pMyEntry;
CGUIDVersion transferSyntax;
CBindingVector * pBVhandles;
int mergeHandles(NSI_SERVER_BINDING_VECTOR_T* pHandles) {
return pBVhandles->merge(pHandles);
}
public:
// constructor for entries from the client
// directly.
CInterface(
NSI_INTERFACE_ID_T * lpInf,
NSI_SERVER_BINDING_VECTOR_T *BindingVector,
CServerEntry *pMyEntry
);
// constructor for entries from the DS.
CInterface(
CServerEntry * pMyEntry,
HANDLE hDSObject,
ADS_SEARCH_HANDLE hSearchHandle,
HRESULT * phr);
RPC_SYNTAX_IDENTIFIER xferSyntaxIdAndVersion() {
return transferSyntax.myIdAndVersion();
}
/* self is the same or a more recent MINOR version for both
interface and transfer syntax IDs */
int isCompatibleWith(
CGUIDVersion * pInterfaceID,
CGUIDVersion * pTransferID
)
{
return (!pInterfaceID || this->isCompatibleGV(*pInterfaceID))
&& (!pTransferID || transferSyntax.isCompatibleGV(*pTransferID));
}
~CInterface() {
delete pBVhandles;
}
BOOL purgeCommonEntries(CInterface *src)
{
return pBVhandles->purgeCommonEntries(src->pBVhandles);
}
// adding this entry to the DS.
HRESULT AddToDS();
HRESULT DeleteFromDS();
};
/*++
Class Definition:
CEntryName
Abstract:
This class encapsulates knowledge about RPC name service entry names.
Data Members:
CStringW (base) -- the name string in its original form
DomainName -- the name of the Domain, without any punctuation
EntryName -- the name of the entry, without any /.: or /... prefix
and also without a domain name at the beginning
--*/
class CEntryName : public CStringW {
protected:
CStringW *pswDomainName;
CStringW *pswEntryName;
CStringW *pswRpcContainerDN;
CStringW *pswDomainNameDns;
public:
CEntryName(CONST_STRING_T fullName); // disassembling constructor
CEntryName( // assembling constructor
CONST_STRING_T domainName,
CONST_STRING_T entryName
);
CEntryName::CEntryName( // assembling constructor for DS
CONST_STRING_T RpcContainerDN,
CONST_STRING_T domainNameDns, // if NULL, assume relative name
DWORD type,
CONST_STRING_T entryName
);
CEntryName()
{
pswDomainName = NULL;
pswEntryName = NULL;
pswRpcContainerDN = NULL;
pswDomainNameDns = NULL;
}
CEntryName& operator=( const CEntryName& EntryName ) {
*(CStringW *)(this) = *((CStringW *)&EntryName);
delete pswDomainName;
delete pswEntryName;
delete pswRpcContainerDN;
delete pswDomainNameDns;
if (EntryName.pswDomainName)
pswDomainName = new CStringW(*EntryName.pswDomainName);
else
pswDomainName = NULL;
if (EntryName.pswEntryName)
pswEntryName = new CStringW(*EntryName.pswEntryName);
else
pswEntryName = NULL;
if (EntryName.pswRpcContainerDN)
pswRpcContainerDN = new CStringW(*EntryName.pswRpcContainerDN);
else
pswRpcContainerDN = NULL;
if (EntryName.pswDomainNameDns)
pswDomainNameDns = new CStringW(*EntryName.pswDomainNameDns);
else
pswDomainNameDns = NULL;
return *this;
}
virtual ~CEntryName(); // base class destructor should be virtual
CStringW* getDomainName();
CStringW* getDomainNameDns();
CStringW* getEntryName()
{
return pswEntryName;
}
void changeToLocalName()
{
delete pswDomainName;
pswDomainName = NULL;
pswDomainNameDns = NULL;
delete [] pszVal;
pszVal = catenate(RelativePrefix,*pswEntryName);
}
STRING_T copyGlobalName();
STRING_T copyCurrentName()
{
return copyString(getCurrentName());
}
STRING_T getFullDNAlloc();
STRING_T getFullDNWithDomainAlloc();
CStringW *getRpcContainer();
STRING_T getCurrentName()
/* this is mainly for use by CEntry objects. for CEntryName objects, automatic
conversion through the inherited STRING_T operator is used instead */
{
return pszVal;
}
int isLocal();
};
typedef TIIterator<CEntryName> TEntryNameIterator;
/*++
Class Definition:
CContextHandle
Abstract:
This is the base interface for all context handles. It is needed
because, for RPC, there is a single NSI_NS_HANDLE_T context handle type,
and there has to be a single entry point for the rundown process.
A virtual destructor is needed for the same reason.
Note that CContextHandle is not an abstract class.
--*/
class CContextHandle {
public:
ULONG ulCacheMax; // max age of a cached item that is acceptable
// *at lookup time* (this is important)
ULONG myLocatorCount; // Locator that I am corresp. to.
ULONG ulCreationTime; // when I was created
virtual void lookupIfNecessary() {} // redo the lookup which created this handle
virtual void setExpiryAge(ULONG newMax) {
ULONG ulOldMax = ulCacheMax;
ulCacheMax = newMax;
if (ulCacheMax < ulOldMax) lookupIfNecessary();
}
virtual void rundown() {}
CContextHandle() {
ulCreationTime = CurrentTime();
myLocatorCount = LocatorCount; // global locator object that this corresponds
// to.
}
virtual ~CContextHandle() {}
};
/*++
Template Class Definition:
CNSHandle
Abstract:
This template defines the basic nature of an NS handle.
It is instantiated into abstract base classes such as
CObjectInqHandle and CLookupHandle, and is also used in
the definition of other templates such as CCompleteHandle
which abstract general properties of classes of handles.
--*/
template <class ItemType>
struct CNSHandle : public CContextHandle
{
public:
ULONG StatusCode;
virtual void lookupIfNecessary() = 0; // redo the lookup which created this handle
virtual ItemType * next() = 0; // primary iterative operation
virtual int finished() = 0; // test for end of iterator
virtual void rundown() = 0; // inherited and still pure virtual
CNSHandle() { StatusCode = NSI_S_OK; }
virtual ULONG getStatus() { return StatusCode; }
virtual ~CNSHandle() {}
};
/*++
Class Definition:
CObjectInqHandle
Abstract:
This is the class for object lookup handles.
The primary operation on a handle is "next" which is inherited
from the TIIterator template interface (instantiated as TGuidIterator
which returns CGUID objects). However, it also needs an additional
operation for the locator-to-locator case where an entire vector of
object UUIDs is returned instead of just one UUID at a time.
--*/
typedef CNSHandle<GUID> CObjectInqHandle;
/*++
Class Definition:
CRemoteObjectInqHandle
Abstract:
This is the common object inquiry handle class for remote entries. Handles based
on nonlocal entries, master locators and broadcast are derived from it. Note that
the connection between a remote handle and a specific entry is very tenuous.
We don't even assume that the entry object(s) the handle was derived from will
exist as long as the handle does. In case of a new lookup being forced (because
handle is too stale -- this happens only with the RpcNsHandleSetExpAge API), we
expect to start all over again from scratch.
--*/
class CRemoteObjectInqHandle : public CObjectInqHandle {
protected:
NSI_UUID_VECTOR_P_T pUuidVector;
ULONG ulIndex;
CEntryName * penEntryName;
ULONG ulEntryNameSyntax;
/* A flag to delay initialization until the first call on next */
BOOL fNotInitialized;
public:
#if DBG
static ULONG ulHandleCount;
ULONG ulHandleNo;
#endif
CRemoteObjectInqHandle(
STRING_T szName,
ULONG ulCacheAge
)
{
DBGOUT(MEM2, "CRemoteObjectInqHandle#" << (ulHandleNo = ++ulHandleCount)
<< " Created at" << CurrentTime() << "\n\n");
penEntryName = szName ? new CEntryName(szName) : NULL;
ulEntryNameSyntax = RPC_C_NS_SYNTAX_DCE;
ulIndex = 0;
fNotInitialized = TRUE;
pUuidVector = NULL;
ulCacheMax = ulCacheAge;
}
virtual ~CRemoteObjectInqHandle()
{
DBGOUT(MEM2, "CRemoteObjectInqHandle#" << (ulHandleCount--,ulHandleNo)
<< " Destroyed at" << CurrentTime() << "\n\n");
rundown();
delete penEntryName;
penEntryName = NULL;
}
virtual void initialize() = 0;
virtual void lookupIfNecessary()
/*
Note that this does not reinitialize the handle
-- that is deferred until a "next" or "finished" call
*/
{
DBGOUT(MEM1,"lookupIfNecessary called for a remote handle\n\n");
if (CurrentTime() - ulCreationTime > ulCacheMax) rundown();
}
/* The rundown method should be extended in a subclass if objects of the subclass
hold additional resources connected with the current contents of the handle (as
opposed to lookup parameters). For additional lookup parameters, a destructor
should be provided instead. */
void rundown()
{
if (pUuidVector)
{
for (; ulIndex < pUuidVector->count; ulIndex++)
midl_user_free(pUuidVector->uuid[ulIndex]);
midl_user_free(pUuidVector);
pUuidVector = NULL;
}
fNotInitialized = TRUE;
}
virtual GUID* next() {
if (fNotInitialized) initialize();
if (finished()) return NULL;
GUID* result = pUuidVector->uuid[ulIndex];
pUuidVector->uuid[ulIndex] = NULL;
ulIndex++;
return result;
}
virtual BOOL finished() {
if (fNotInitialized) initialize();
return StatusCode || !pUuidVector || (ulIndex >= pUuidVector->count);
}
};
/*++
Class Definition:
CNetObjectInqHandle
Abstract:
This is the common object inquiry handle class for network-based object inquiry.
Since net object inquiry is now "lazy" (net is accessed only if needed), we need
a lazy handle which initializes itself according to the old pattern of
"use master if you can, broadcast if you must".
--*/
class CNetObjectInqHandle : public CRemoteObjectInqHandle {
CRemoteObjectInqHandle *pRealHandle;
virtual void initialize();
public:
ULONG getStatus() { return pRealHandle->StatusCode; }
virtual void rundown()
{
if (pRealHandle)
{
pRealHandle->rundown();
delete pRealHandle;
pRealHandle = NULL;
}
fNotInitialized = TRUE;
}
CNetObjectInqHandle(
STRING_T EntryName,
unsigned long ulCacheAge
) :
CRemoteObjectInqHandle(
EntryName,
ulCacheAge
)
{
pRealHandle = NULL;
fNotInitialized = TRUE;
}
~CNetObjectInqHandle()
{
rundown();
}
GUID *next() {
if (fNotInitialized) initialize();
return pRealHandle->next();
}
int finished() {
if (fNotInitialized) initialize();
return pRealHandle->finished();
}
};
/*++
Class Definition:
CLookupHandle
Abstract:
This is the base class for BV lookup handles. Actual handles
belong to derived classes corresponding to entry types.
The primary operation on a handle is "next" which is inherited
from the TIIterator template interface (instantiated as TBVIterator).
There is the possibility that a longlived client will fail to
release a lookup handle, causing an effective leak of resources,
but we won't deal with that in the current version.
--*/
typedef CNSHandle<NSI_BINDING_VECTOR_T> CLookupHandle;
/*++
Class Definition:
CNullLookupHandle
Abstract:
This is used when a lookup handle is required but there is nothing
to look up. Always returns NULL.
--*/
class CNullLookupHandle : public CLookupHandle
{
public:
virtual void lookupIfNecessary() {}
virtual NSI_BINDING_VECTOR_T * next() { return NULL; }
virtual int finished() { return TRUE; }
virtual void rundown() {}
};
/*++
Class Definition:
CMailSlotReplyHandle
Abstract:
This is the base class for handles which provide items for constructing
mailslot reply buffers. Actual handles belong to derived classes
corresponding to entry types.
The primary operation on a handle is "next" which is inherited
from the TIIterator template interface (instantiated as TMSRIIterator).
--*/
class CMailSlotReplyHandle : public TMSRIIterator {
public:
virtual ~CMailSlotReplyHandle() {}
};
/*++
Class Definition:
CEntry
Abstract:
The base Entry class for the internal cache. Even though this is an abstract
class due to the unspecified loopup member, the class is not a pure
interface (it has a constructor), hence the C rather than I prefix in the name.
Note that CEntry has only constant data members.
--*/
class CEntry : public CEntryName {
const EntryType type;
public:
const unsigned long ulEntryNameSyntax;
CEntry(
CONST_STRING_T pszStr,
const EntryType& e,
const unsigned long ulSyntax = RPC_C_NS_SYNTAX_DCE
)
: CEntryName( pszStr ),
ulEntryNameSyntax(ulSyntax),
type(e)
{}
CEntry(
CONST_STRING_T pszRpcContainerDN,
CONST_STRING_T pszDomainNameDns,
DWORD Domaintype,
CONST_STRING_T pszEntryName,
const EntryType& e,
const unsigned long ulSyntax = RPC_C_NS_SYNTAX_DCE
)
: CEntryName( pszRpcContainerDN, pszDomainNameDns, Domaintype, pszEntryName ),
ulEntryNameSyntax(ulSyntax),
type(e)
{}
virtual ~CEntry() {}
EntryType getType() { return type; }
BOOL isNonLocalType() {
switch (type) {
case NonLocalServerEntryType: return TRUE;
default: return FALSE;
}
}
virtual void flush() {} // useful for cache flushing, for instance
virtual BOOL isCurrent(ULONG) { return TRUE; } // QUESTION: again cache oriented
// need CNonLocalEntryMixin for these?
virtual BOOL isEmpty() = 0;
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
) = 0;
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
) = 0;
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
) = 0;
virtual HRESULT DeleteFromDS() {return S_OK;};
// this method is added so that this can be called
// for nsi_delete irresp. of the kind of entry. should
// be redefined in all the entries that have to be deleted.
};
typedef TCGuardedSkipList<CFullServerEntry> TGSLEntryList;
typedef TCGuardedSkipListIterator<CEntry> TGSLEntryListIterator;
typedef TCSafeSkipList<CEntry> TSSLEntryList;
typedef TCSafeSkipListIterator<CEntry> TSSLEntryListIterator;
typedef TCSafeLinkList<CEntry> TSLLEntryList;
typedef TCSafeLinkListIterator<CEntry> TSLLEntryListIterator;
typedef TISkipList<CEntry> TEntrySkipList;
typedef TIIterator<CEntry> TEntryIterator;
/*++
Class Definition:
CRemoteLookupHandle
Abstract:
This is the common lookup handle class for remote entries. Handles based on
NonLocal entries, master locators and broadcast are derived from it. Note that
the connection between a remote handle and a specific entry is very tenuous.
We don't even assume that the entry object(s) the handle was derived from will
exist as long as the handle does. In case of a renewal lookup (lookupIfNecessary())
being forced, we expect to start all over again from scratch.
This handle, like all NS handles, relies on the fact that it is accessed
as a client handle by the client side, and hence the RPC run-time
automatically serializes its use.
--*/
class CRemoteLookupHandle : public CLookupHandle {
protected:
/* caching parameters */
UNSIGNED32 u32EntryNameSyntax;
CEntryName * penEntryName;
CGUIDVersion * pgvInterface;
CGUIDVersion * pgvTransferSyntax;
CGUID * pidObject;
ULONG ulVS;
/* List of temporary entries created as a cache local to this
handle by fetchNext. Must keep it for proper disposal
after its use is finished. This is only used in net
handles -- CMasterLookupHandle and CBroadcastLookupHandle
*/
TSSLEntryList *psslNewCache;
/* a lookup handle based on prefetched info */
CLookupHandle *plhFetched;
/* A flag to delay initialization until the first call on next */
BOOL fNotInitialized;
public:
#if DBG
static ULONG ulHandleCount;
ULONG ulHandleNo;
#endif
CRemoteLookupHandle(
UNSIGNED32 EntryNameSyntax,
STRING_T EntryName,
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual void initialize() = 0;
/* The rundown method should be extended in a subclass if objects of the subclass
hold additional resources connected with the current contents of the handle (as
opposed to lookup parameters). See CMasterLookupHandle::rundown for an example.
For additional lookup parameters, a destructor should be provided instead.
*/
virtual void rundown()
{
if (plhFetched) {
plhFetched->rundown();
delete plhFetched;
plhFetched = NULL;
}
if (psslNewCache) {
psslNewCache->wipeOut();
delete psslNewCache;
psslNewCache = NULL;
}
fNotInitialized = TRUE;
}
virtual ~CRemoteLookupHandle() {
DBGOUT(MEM2, "RemoteLookupHandle#" << (ulHandleCount--,ulHandleNo)
<< " Destroyed at" << CurrentTime() << "\n\n");
rundown();
delete pgvInterface;
delete pgvTransferSyntax;
delete pidObject;
delete penEntryName;
}
virtual void setExpiryAge(ULONG newMax) {
ULONG ulOldMax = ulCacheMax;
DBGOUT(TRACE, "Setting the expiry age to " << newMax << "\n");
DBGOUT(TRACE, "The old expiry age is " << ulOldMax << "\n");
ulCacheMax = newMax;
if (plhFetched) plhFetched->setExpiryAge(newMax);
if (ulCacheMax < ulOldMax) lookupIfNecessary();
}
virtual void lookupIfNecessary() // standard behavior is:
/*
Note that this does not reinitialize the handle
-- that is deferred until a "next" or "finished" call
*/
{
DBGOUT(TRACE, "Calling lookupifnecessary in remotelookupHandle\n");
if (CurrentTime() - ulCreationTime > ulCacheMax) rundown();
}
virtual int finished() { // default behavior
if (fNotInitialized) initialize();
return !plhFetched || plhFetched->finished();
}
virtual NSI_BINDING_VECTOR_T *next() { // default behavior
if (fNotInitialized) initialize();
return plhFetched ? plhFetched->next() : NULL;
}
};
/*++
Class Definition:
CNetLookupHandle
Abstract:
This is the common lookup handle class for network-based lookup.
Since net lookup is now "lazy" (net is accessed only if needed), we need
a lazy handle which initializes itself according to the old pattern of
"use master if you can, broadcast if you must".
--*/
class CNetLookupHandle : public CRemoteLookupHandle {
CRemoteLookupHandle *pRealHandle;
virtual void initialize();
#if DBG
static ULONG ulNetLookupHandleCount;
static ULONG ulNetLookupHandleNo;
ULONG ulHandleNo;
#endif
public:
ULONG getStatus() { return pRealHandle->StatusCode; }
virtual void rundown()
{
DBGOUT(TRACE,"CNetLookupHandle::rundown called for Handle#" << ulHandleNo << "\n\n");
if (pRealHandle)
{
pRealHandle->rundown();
delete pRealHandle;
pRealHandle = NULL;
}
fNotInitialized = TRUE;
}
CNetLookupHandle(
UNSIGNED32 EntryNameSyntax,
STRING_T EntryName,
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
) :
CRemoteLookupHandle(
EntryNameSyntax,
EntryName,
pGVInterface,
pGVTransferSyntax,
pIDobject,
ulVectorSize,
ulCacheAge
)
{
pRealHandle = NULL;
fNotInitialized = TRUE;
#if DBG
ulNetLookupHandleCount++;
ulHandleNo = ++ulNetLookupHandleNo;
#endif
}
~CNetLookupHandle()
{
rundown();
#if DBG
ulNetLookupHandleCount--;
#endif
}
NSI_BINDING_VECTOR_T *next() {
DBGOUT(TRACE,"CNetLookupHandle::next called for Handle#" << ulHandleNo << "\n\n");
if (fNotInitialized) initialize();
return pRealHandle->next();
}
int finished() {
DBGOUT(TRACE,"CNetLookupHandle::finished called for Handle#" << ulHandleNo << "\n\n");
if (fNotInitialized) initialize();
return pRealHandle->finished();
}
};
/*++
Class Definition:
CDSLookupHandle
Abstract:
DS lookup handle. It is lazy and gets the data only when next is called.
--*/
class CDSLookupHandle : public CLookupHandle {
BOOL fNotInitialized;
UNSIGNED32 u32EntryNameSyntax;
CEntryName * penEntryName;
CGUIDVersion * pgvInterface;
CGUIDVersion * pgvTransferSyntax;
CGUID * pidObject;
ULONG ulVS;
void initialize();
CLookupHandle *pRealHandle;
CEntry *pEntry;
#if DBG
static ULONG ulDSLookupHandleCount;
static ULONG ulDSLookupHandleNo;
ULONG ulHandleNo;
#endif
public:
virtual void rundown()
{
DBGOUT(TRACE,"CDSLookupHandle::rundown called for Handle#" << ulHandleNo << "\n\n");
if (pRealHandle)
{
pRealHandle->rundown();
delete pRealHandle;
pRealHandle = NULL;
}
delete pEntry;
fNotInitialized = TRUE;
}
CDSLookupHandle(
UNSIGNED32 EntryNameSyntax,
STRING_T EntryName,
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
)
{
DBGOUT(MEM2, "DSLookupHandle#" << (ulHandleNo = ++ulDSLookupHandleCount)
<< " Created at" << CurrentTime() << "\n\n");
u32EntryNameSyntax = EntryNameSyntax;
penEntryName = EntryName ? new CEntryName(EntryName) : NULL;
pgvInterface = pGVInterface ? new CGUIDVersion(*pGVInterface) : NULL;
pgvTransferSyntax = pGVTransferSyntax ?
new CGUIDVersion(*pGVTransferSyntax) :
NULL;
pidObject = pIDobject ? new CGUID(*pIDobject) : NULL;
ulVS = ulVectorSize;
fNotInitialized = TRUE;
pEntry = NULL;
pRealHandle = NULL;
#if DBG
ulHandleNo = ++ulDSLookupHandleNo;
#endif
}
~CDSLookupHandle()
{
rundown();
#if DBG
ulDSLookupHandleCount--;
#endif
}
void lookupIfNecessary() {};
NSI_BINDING_VECTOR_T *next() {
DBGOUT(TRACE,"CDSLookupHandle::next called for Handle#" << ulHandleNo << "\n\n");
if (fNotInitialized)
initialize();
if (pRealHandle)
return pRealHandle->next();
else
return NULL;
}
int finished() {
DBGOUT(TRACE,"CDSLookupHandle::finished called for Handle#" << ulHandleNo << "\n\n");
if (fNotInitialized) initialize();
return pRealHandle?pRealHandle->finished():TRUE;
}
int FoundInDS()
{
if (fNotInitialized) initialize();
return (pRealHandle?TRUE:FALSE);
}
};
/*++
Class Definition:
CServerObjectInqHandle
Abstract:
This is the object inquiry handle class for local (owned) server entries.
Since NS handles are used as context handles in RPC calls, the RPC runtime
guarantees serialization and we do not need to use critical sections explicitly.
--*/
class CServerObjectInqHandle : public CObjectInqHandle {
TGuidIterator *pcgIterSource;
public:
CServerObjectInqHandle(
TGuidIterator *pHandle,
ULONG cacheMax = 0
) : pcgIterSource(pHandle)
{
ulCacheMax = cacheMax;
}
GUID *next();
virtual void lookupIfNecessary() {} // never redo lookup for local info
int finished() {
return pcgIterSource->finished();
}
virtual ~CServerObjectInqHandle() {
rundown();
}
virtual void rundown();
};
/*++
Class Definition:
CServerEntry
Abstract:
The specific Entry class for entries with binding and object attributes.
--*/
class CServerEntry : public CEntry {
protected:
TCSafeSkipList<CGUID> ObjectList; // object attribute
TCSafeSkipList<CInterface> InterfaceList; // binding attribute
TSLLString*
CServerEntry::formObjectStrings(
CGUID* pIDobject
);
public:
// constructors for different kind of lookups in DS.
CServerEntry(CONST_STRING_T pszStr, ADS_ATTR_INFO *pAttr, DWORD cAttr,
HANDLE hDSObject, HRESULT *phr);
CServerEntry(CONST_STRING_T pszRpcContainerDN, CONST_STRING_T pszDomainName, CONST_STRING_T pszEntryName,
HANDLE hDSObject, ADS_SEARCH_HANDLE hSearchHandle, HRESULT *phr);
CServerEntry(CONST_STRING_T pszStr)
: CEntry(pszStr, ServerEntryType)
{}
CServerEntry(CONST_STRING_T pszStr, const EntryType type)
: CEntry(pszStr, type)
{
}
virtual void flush(); // inherited from CEntry
virtual BOOL isEmpty() {
CriticalReader me(rwEntryGuard);
return (ObjectList.size() == 0) && (InterfaceList.size() == 0);
}
virtual ~CServerEntry() { // NonLocal version could be derived from it
flush();
}
virtual int addObjects(NSI_UUID_VECTOR_P_T ObjectVector);
virtual int removeObjects(
NSI_UUID_VECTOR_P_T ObjectVector,
int& fRemovedAll
);
virtual int addToInterface(
NSI_INTERFACE_ID_T *,
NSI_SERVER_BINDING_VECTOR_T *,
CInterfaceIndex *
);
virtual int addInterfaceToDS(
NSI_INTERFACE_ID_T *,
NSI_SERVER_BINDING_VECTOR_T *
);
virtual int removeInterfaces(
NSI_IF_ID_P_T Interface,
UNSIGNED32 VersOption,
CInterfaceIndex *
);
virtual int removeInterfacesFromDS(
NSI_IF_ID_P_T Interface,
UNSIGNED32 VersOption
);
int add_to_entry(
IN NSI_INTERFACE_ID_T * Interface,
IN NSI_SERVER_BINDING_VECTOR_T * BindingVector,
IN NSI_UUID_VECTOR_P_T ObjectVector,
CInterfaceIndex *,
BOOL fCache
);
int remove_from_entry(
IN NSI_IF_ID_P_T Interface,
IN UNSIGNED32 VersOption,
IN NSI_UUID_VECTOR_P_T ObjectVector,
CInterfaceIndex * IfIndex
);
int
add_changes_to_DS(
IN NSI_INTERFACE_ID_T * Interface,
IN NSI_SERVER_BINDING_VECTOR_T * BindingVector,
IN NSI_UUID_VECTOR_P_T ObjectVector,
BOOL fNewEntry,
BOOL fIgnoreErrors
);
int remove_changes_from_DS(
IN NSI_IF_ID_P_T Interface,
IN UNSIGNED32 VersOption,
IN NSI_UUID_VECTOR_P_T ObjectVector,
BOOL fIgnoreErrors
);
int memberObject(CGUID *obj) {
CriticalReader me(rwEntryGuard);
return ObjectList.find(obj) != NULL;
}
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge // ignored in this case
);
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
);
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
);
HRESULT AddToDS();
HRESULT DeleteFromDS();
BOOL purgeCommonEntries(CServerEntry *src)
{
int i, j, sz = ObjectList.size(), sz1;
CGUID *pguid1, *pguid2;
TSSLGuidIterator piter(ObjectList);
TCSafeSkipListIterator<CInterface> pint1Iterator(InterfaceList);
CInterface *pint1, *pint2;
for (i = 0; i < sz; i++)
{
pguid2 = piter.next();
pguid1 = (src->ObjectList).find(pguid2);
if (pguid1)
{
ObjectList.remove(pguid1);
}
}
sz = InterfaceList.size();
sz1 = (src->InterfaceList).size();
for (i = 0; i < sz; i++)
{
TCSafeSkipListIterator<CInterface> pint2Iterator(src->InterfaceList);
pint1 = pint1Iterator.next();
for (j = 0; j < sz1; j++)
{
pint2 = pint2Iterator.next();
if ((pint1) && (pint2))
if (pint1->purgeCommonEntries(pint2))
{
InterfaceList.remove(pint1);
delete pint1;
}
}
}
if (InterfaceList.size())
return FALSE;
else
return TRUE;
}
};
/*++
Class Definition:
CNonLocalServerEntry
Abstract:
A variation on CServerEntry with modifications to reflect the fact that the
info is NonLocal rather than owned by the locator, including a notion of being
current based on the earliest caching time of any info in the entry. Note that
info may be added incrementally at various times.
--*/
class CNonLocalServerEntry : public CServerEntry {
ULONG ulCacheTime;
public:
int fHasNonLocalInfo;
virtual BOOL isCurrent(ULONG ulTolerance);
CNonLocalServerEntry(
CONST_STRING_T pszStr
)
: CServerEntry(pszStr,NonLocalServerEntryType)
{
fHasNonLocalInfo = FALSE;
ulCacheTime = 0;
}
virtual void flush()
{
CServerEntry::flush();
CriticalWriter me(rwNonLocalEntryGuard);
DBGOUT(OBJECT, "\nFlushing CNonLocalServerEntry\n");
DBGOUT(OBJECT, "EntryName = " << getCurrentName() << WNL);
DBGOUT(OBJECT, "This entry has a ulCacheTime = " << ulCacheTime << "\n\n");
fHasNonLocalInfo = FALSE;
}
int addObjects(NSI_UUID_VECTOR_P_T ObjectVector) {
{
CriticalWriter me(rwNonLocalEntryGuard);
if (!fHasNonLocalInfo) {
ulCacheTime = CurrentTime();
fHasNonLocalInfo = TRUE;
}
else {
DBGOUT(OBJECT, "\nPerforming addObjects on a nonempty entry\n");
DBGOUT(OBJECT, "EntryName = " << getCurrentName() << WNL);
DBGOUT(OBJECT, "This entry has a ulCacheTime = " << ulCacheTime << WNL);
DBGOUT(OBJECT, "Current Time = " << CurrentTime() << "\n\n");
DBGOUT(OBJECT, "The Objects:\n" << ObjectVector);
}
}
return CServerEntry::addObjects(ObjectVector);
}
int addToInterface(
NSI_INTERFACE_ID_T * pInf,
NSI_SERVER_BINDING_VECTOR_T * pBVT,
CInterfaceIndex * pIndex
)
{
{
CriticalWriter me(rwNonLocalEntryGuard);
if (!fHasNonLocalInfo) {
ulCacheTime = CurrentTime();
fHasNonLocalInfo = TRUE;
}
else {
DBGOUT(OBJECT, "\nPerforming addToInterface on a nonempty entry\n");
DBGOUT(OBJECT, "EntryName = " << getCurrentName() << WNL);
DBGOUT(OBJECT, "This entry has a ulCacheTime = " << ulCacheTime << WNL);
DBGOUT(OBJECT, "Current Time = " << CurrentTime() << WNL << WNL);
DBGOUT(OBJECT, "The Bindings:\n" << pBVT);
}
}
return CServerEntry::addToInterface(pInf, pBVT, pIndex);
}
int removeObjects( // shouldn't happen to a NonLocal entry
NSI_UUID_VECTOR_P_T ObjectVector,
int& fRemovedAll
)
{
Raise(NSI_S_ENTRY_NOT_FOUND);
/* the following just keeps the compiler happy */
return FALSE;
}
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
);
int removeInterfaces( // shouldn't happen to a NonLocal entry
NSI_IF_ID_P_T Interface,
UNSIGNED32 VersOption,
CInterfaceIndex &
)
{
Raise(NSI_S_ENTRY_NOT_FOUND);
/* the following just keeps the compiler happy */
return FALSE;
}
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
)
// NonLocal info is not returned in response to a broadcast, hence
{
return NULL;
}
};
/*++
Class Definition:
CFullServerEntry
Abstract:
This class is used to account for the fact that direct exports to
the same server entry may be made on two different machines.
As a result, the information in a server entry is partly nonlocal
remote handles and partly locally exported handles. Two kinds of
server entries within itself.
--*/
class CFullServerEntry : public CEntry {
BOOL fNetLookupDone;
void flushCacheIfNecessary(ULONG ulTolerance);
CServerEntry *pLocalEntry;
CNonLocalServerEntry *pNonLocalEntry;
public:
CServerEntry *getLocal() {
CriticalReader me(rwFullEntryGuard);
return pLocalEntry;
}
CNonLocalServerEntry *getNonLocal() {
CriticalReader me(rwFullEntryGuard);
return pNonLocalEntry;
}
CFullServerEntry(
CONST_STRING_T pszName
)
:CEntry(
pszName,
FullServerEntryType
)
{
pLocalEntry = new CServerEntry(pszName);
pNonLocalEntry = new CNonLocalServerEntry(pszName);
fNetLookupDone = FALSE;
}
virtual ~CFullServerEntry() {
delete pLocalEntry;
delete pNonLocalEntry;
}
virtual BOOL isEmpty() {
CriticalReader me(rwFullEntryGuard);
return pLocalEntry->isEmpty() && pNonLocalEntry->isEmpty();
}
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
);
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
);
};
/*++
Class Definition:
CNonLocalServerObjectInqHandle
Abstract:
This is the object inquiry handle class for NonLocal server entries.
The only difference from a local CServerObjectInqHandle is
the functionality added by CRemoteObjectInqHandle.
--*/
class CNonLocalServerObjectInqHandle : public CRemoteObjectInqHandle {
void initialize();
public:
CNonLocalServerObjectInqHandle(
STRING_T pszName,
ULONG ulCacheAge
);
};
class CGroupInqHandle;
/*++
Class Definition:
CGroupEntry
Abstract:
--*/
class CGroupEntry : public CEntry {
protected:
TCSafeSkipList<CEntryName> GroupList;
public:
CGroupEntry(const STRING_T pszStr, ADS_ATTR_INFO *pAttr,
DWORD cAttr, HANDLE hDSObject,
HRESULT *phr);
CGroupEntry(const STRING_T pszStr)
: CEntry(pszStr, GroupEntryType)
{}
CGroupInqHandle * GroupMbrInquiry();
void AddMember(
STRING_T pEntryName
)
{
HRESULT hr = S_OK;
// First parse the name anyway
CEntryName *pName = new CEntryName(pEntryName);
// Now see if we have it already
if (GroupList.insert(pName) == Duplicate)
{
delete pName;
}
else
{
hr = AddToDS();
if (FAILED(hr)) {
DWORD dwErr = RemapErrorCode(hr);
if (dwErr == NSI_S_INTERNAL_ERROR)
Raise(NSI_S_GRP_ELT_NOT_ADDED);
else
Raise(dwErr);
}
}
}
void RemoveMember(
STRING_T pEntryName
)
{
HRESULT hr = S_OK;
if (GroupList.remove(&CEntryName(pEntryName)))
hr = AddToDS();
if (FAILED(hr)) {
DWORD dwErr = RemapErrorCode(hr);
if (dwErr == NSI_S_INTERNAL_ERROR)
Raise(NSI_S_GRP_ELT_NOT_REMOVED);
else
Raise(dwErr);
}
}
virtual BOOL isEmpty() { return GroupList.size() == 0; }
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
)
{
// We don't support object attributes in group entries
return NULL;
}
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
)
{
// Group entries don't participate in legacy mechanisms
return NULL;
}
HRESULT AddToDS();
HRESULT DeleteFromDS();
};
/*++
Class Definition:
CGroupInqHandle
Abstract:
This is the handle class for enumerating group entries via the
RpcNsGroupMbrInq set of APIs.
--*/
class CGroupInqHandle : public CNSHandle<WCHAR>
{
TEntryNameIterator *pNameIter;
CGroupEntry *pmyGroup;
public:
// redo the lookup which created this handle
virtual void lookupIfNecessary() {}
virtual STRING_T next()
{
CEntryName* pName = pNameIter->next();
STRING_T result = NULL;
if (pName)
{
result = pName->copyAsMIDLstring();
}
return result;
}
virtual int finished()
{
return pNameIter->finished();
}
virtual void rundown()
{
delete pNameIter;
pNameIter = NULL;
delete pmyGroup;
pmyGroup = NULL;
}
CGroupInqHandle(TEntryNameIterator *pIter, CGroupEntry *pGroup)
: pNameIter(pIter),
pmyGroup(pGroup)
{}
virtual ~CGroupInqHandle()
{
rundown();
}
};
/*++
Class Definition:
CProfileKey
Abstract:
Inherits from CGUIDVersion which represents
the interface ID for the element, and CEntryName.
Name comparison takes priority over interface comparison.
--*/
struct CProfileKey : public IOrderedItem
{
CGUIDVersion Interface;
CEntryName EntryName;
CProfileKey(
RPC_SYNTAX_IDENTIFIER * pInterface,
STRING_T pEntryName
)
:
EntryName(pEntryName)
{
if (pInterface != NULL)
{
// call the copy constructor
Interface = CGUIDVersion(*pInterface);
}
else
{
RPC_SYNTAX_IDENTIFIER * pnewInterface = new RPC_SYNTAX_IDENTIFIER;
memset(pnewInterface, 0, sizeof(RPC_SYNTAX_IDENTIFIER));
Interface = CGUIDVersion(*pnewInterface);
delete pnewInterface;
// create an interface with all zeroes.
}
}
CProfileKey()
{};
virtual int compare(const IOrderedItem& other)
{
CProfileKey& otherKey = (CProfileKey&) other;
BOOL nameComp = EntryName.compare(otherKey.EntryName);
BOOL interfaceComp = Interface.compare(otherKey.Interface);
return nameComp == 0 ? interfaceComp : nameComp;
}
BOOL matches(
CEntryName *pEntryName,
CGUIDVersion* pInterface,
UNSIGNED32 vers_option
)
{
BOOL fNameMatches = pEntryName ? EntryName == *pEntryName : TRUE;
BOOL fInterfaceMatches = pInterface
? Interface.isMatching(*pInterface,vers_option)
: TRUE;
return fNameMatches && fInterfaceMatches;
}
};
class CProfileEntry;
/*++
Class Definition:
CProfileElement
Abstract:
Inherits from CGUIDVersion which represents
the interface ID for the element
--*/
struct CProfileElement : public CProfileKey {
CProfileElement(
RPC_SYNTAX_IDENTIFIER * pInterface,
STRING_T pEntryName,
DWORD dwPriority,
STRING_T pszAnnotation,
CProfileEntry * pMyEntry
)
: CProfileKey(pInterface,pEntryName),
dwPriority(dwPriority),
pszAnnotation(pszAnnotation),
m_pMyEntry(pMyEntry)
{
}
// constructor for the DS lookup
CProfileElement(
CProfileEntry * pMyEntry,
HANDLE hDSObject,
ADS_SEARCH_HANDLE hSearchHandle,
HRESULT * phr
);
~CProfileElement()
{
}
DWORD dwPriority;
BOOL fIsDefault;
CStringW pszAnnotation;
CProfileEntry * m_pMyEntry;
HRESULT AddToDS();
HRESULT DeleteFromDS();
};
/*++
Class Definition:
CProfileSet
Abstract:
A set of profile elements of the same priority.
--*/
class CProfileSet : public CUnsigned32, // the priority
public TCSafeLinkList<CProfileElement>
{
public:
CProfileSet(CProfileElement *pElt) : CUnsigned32(pElt->dwPriority)
{
insert(pElt);
}
};
class CProfileInqHandle;
/*++
Class Definition:
CProfileEntry
Abstract:
--*/
class CProfileEntry : public CEntry {
protected:
CProfileElement * pDefaultElt;
TCSafeSkipList<CProfileSet> ProfileList; // A skiplist of profile element lists
// ordered by priority
TCSafeSkipList<CProfileElement> EltList; // A skiplist of individual elements
// ordered by entry name
public:
CProfileEntry(const STRING_T pszStr, ADS_ATTR_INFO *pAttr,
DWORD cAttr, HANDLE hDSObject, HRESULT *phr);
CProfileEntry(const STRING_T pszStr)
: CEntry(pszStr, ProfileEntryType),
pDefaultElt(NULL)
{
}
~CProfileEntry()
{
}
CProfileInqHandle * ProfileEltInquiry(
DWORD inquiry_type,
NSI_IF_ID_P_T if_id,
DWORD vers_option,
STRING_T member_name
);
void AddElement(
RPC_SYNTAX_IDENTIFIER * pInterface,
STRING_T pEntryName,
DWORD dwPriority,
STRING_T pszAnnotation
);
void RemoveElement(
RPC_SYNTAX_IDENTIFIER * pInterface,
STRING_T pEntryName
)
{
HRESULT hr = S_OK;
if (pInterface == NULL)
{
if (pDefaultElt)
{
hr = pDefaultElt->DeleteFromDS();
if (FAILED(hr)) {
DWORD dwErr = RemapErrorCode(hr);
if (dwErr == NSI_S_INTERNAL_ERROR)
Raise(NSI_S_PRF_ELT_NOT_REMOVED);
else
Raise(dwErr);
}
delete pDefaultElt;
pDefaultElt = NULL;
return;
}
else
return;
}
CProfileElement *pElt = EltList.remove(&CProfileKey(pInterface,pEntryName));
if (pElt != 0)
{
hr = pElt->DeleteFromDS();
if (FAILED(hr)) {
DWORD dwErr = RemapErrorCode(hr);
if (dwErr == NSI_S_INTERNAL_ERROR)
Raise(NSI_S_PRF_ELT_NOT_REMOVED);
else
Raise(dwErr);
}
// we actually have it, so remove it from the profile lists
CProfileSet *pSet = ProfileList.find(&CUnsigned32(pElt->dwPriority));
ASSERT(pSet, "Inconsistent Profile Entry\n");
BOOL fRemoved = pSet->remove(pElt);
ASSERT(fRemoved, "Inconsistent Profile Entry\n");
if (pSet->size() == 0)
{
ProfileList.remove(pSet);
}
}
}
virtual BOOL isEmpty()
{
return EltList.size() == 0 && pDefaultElt == NULL;
}
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
)
{
// We don't support object attributes in profile entries
return NULL;
}
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
)
{
// Profile entries don't participate in legacy mechanisms
return NULL;
}
HRESULT AddToDS();
HRESULT DeleteFromDS();
};
/*++
Class Definition:
CProfileInqHandle
Abstract:
This is the handle class for enumerating profile entries via the
RpcNsProfileEltInq set of APIs.
--*/
class CProfileInqHandle : public CNSHandle<CProfileElement>
{
TIIterator<CProfileElement> *pEltIter;
CProfileEntry *pmyProfile;
public:
// redo the lookup which created this handle
virtual void lookupIfNecessary() {}
virtual CProfileElement * next()
{
return pEltIter->next();
}
virtual int finished()
{
return pEltIter->finished();
}
virtual void rundown()
{
delete pEltIter;
pEltIter = NULL;
delete pmyProfile;
pmyProfile = NULL;
}
CProfileInqHandle(TIIterator<CProfileElement> *pIter, CProfileEntry *pProfile)
: pEltIter(pIter),
pmyProfile(pProfile)
{}
virtual ~CProfileInqHandle()
{
rundown();
}
};
// entry type and the name is used for comparison.
// this kind of entry is used in maintaining the
// visited list in the group lookup handle.
class CVisitedEntry : public IOrderedItem {
protected:
CStringW * m_pname;
EntryType m_type;
public:
CVisitedEntry(CStringW name, EntryType type) {
m_pname = new CStringW(name);
m_type = type;
}
~CVisitedEntry() {
delete m_pname;
}
virtual int compare( const IOrderedItem& O )
{
const CVisitedEntry& arg = (CVisitedEntry&) O;
int namecompare = m_pname->compare(*(arg.m_pname));
int ret;
if (namecompare == 0)
ret = ((arg.m_type < m_type)? 1 :
((arg.m_type == m_type)? 0 : -1));
else
ret = namecompare;
DBGOUT(TRACE, "!! Types are " << arg.m_type << m_type << "\n");
DBGOUT(TRACE, "!! Comparison returns" << ret << "\n");
return ret;
}
};
typedef TCSafeSkipList<CVisitedEntry> TSSLVisitedList;
/*++
Class Definition:
CMemberEntry
Abstract:
The Entry class for group and profile lookup. Since we only have names
in group and profile entries, when a lookup handle is constructed, we don't
have any guarantee that there are real entries corresponding to those names.
We therefore have this shell class that materializes the real entry when a
lookup is performed on it. This also serves as the logical point for
circularity detection and avoidance in group/profile lookup.
--*/
class CMemberEntry : public CEntry {
CEntry *pRealEntry;
TSSLVisitedList *pVisitedEntries;
void materialize(); // get the real entry now
public:
CMemberEntry(const STRING_T pszStr)
: CEntry(pszStr, MemberEntryType)
{}
~CMemberEntry()
{
if (pRealEntry)
delete pRealEntry;
}
void setVisitedEntries(TSSLVisitedList *pVisited)
{
pVisitedEntries = pVisited;
}
virtual BOOL isEmpty()
{
materialize();
return pRealEntry ? pRealEntry->isEmpty() : TRUE;
}
virtual CLookupHandle * lookup(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual CObjectInqHandle * objectInquiry(
unsigned long ulCacheAge
)
{
materialize();
return pRealEntry
? pRealEntry->objectInquiry(
ulCacheAge
)
: NULL;
}
virtual CMailSlotReplyHandle * MailSlotLookup(
CGUIDVersion * pGVInterface,
CGUID * pIDobject
)
{
// this functionality is not available for hypothetical entries
return NULL;
}
};
/*++
Class Definition:
CServerLookupHandle
Abstract:
This is the binding lookup handle class for local (owned) server entries.
Since NS handles are used as context handles in RPC calls, the RPC runtime
guarantees serialization and we do not need to use critical sections explicitly.
--*/
class CServerLookupHandle : public CLookupHandle {
unsigned long ulVectorSize;
TBVIterator *pBVIterator;
public:
CServerLookupHandle(
TBVSafeLinkList * pBVLL
);
virtual ~CServerLookupHandle() {
rundown();
}
virtual void lookupIfNecessary() {} // never redo lookup for local info
NSI_BINDING_VECTOR_T *next()
{
if (pBVIterator->finished())
return NULL;
CBVWrapper *pBVW = pBVIterator->next();
NSI_BINDING_VECTOR_T *pResult = pBVW->pBVT; // unwrap
delete pBVW; // throw away wrapper
return pResult;
}
int finished() {
return pBVIterator->finished();
}
virtual void rundown();
};
/*++
Class Definition:
CNonLocalServerLookupHandle
Abstract:
This is the lookup handle class for NonLocal server entries.
The only difference from a local CServerLookupHandle is
the functionality added by CRemoteLookupHandle.
--*/
class CNonLocalServerLookupHandle : public CRemoteLookupHandle {
void initialize();
public:
CNonLocalServerLookupHandle(
STRING_T pszName,
CGUIDVersion *pGVInterface,
CGUIDVersion *pGVTransferSyntax,
CGUID *pIDobject,
ULONG ulVectorSize,
ULONG ulCacheAge
);
};
/*++
Class Definition:
CGroupLookupHandle
Abstract:
This is the lookup handle class for group entries and other groups.
Its primary use currently is to produce handles for null-entry
lookups where information from multiple entries needs to be collected.
--*/
class CGroupLookupHandle : public CLookupHandle {
protected:
/* search parameters */
CGUIDVersion * pGVInterface;
CGUIDVersion * pGVTransferSyntax;
CGUID * pIDobject;
unsigned long ulVectorSize;
BOOL fUnusedHandle;
BOOL fRootHandle;
/* Iterator for entries in the group -- please use a guarded kind! */
TEntryIterator *pEIterator;
/* handle for the currently active entry */
CLookupHandle * pCurrentHandle;
/* SkipList of all entries visited so far -- circularity avoidance */
TSSLVisitedList *pVisitedEntries;
void advanceCurrentHandle(); // look for next nonempty entry handle
public:
CGroupLookupHandle(
TEntryIterator * pEI,
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual ~CGroupLookupHandle() {
rundown();
delete pEIterator;
delete pGVInterface;
delete pGVTransferSyntax;
delete pIDobject;
if (fRootHandle)
{
pVisitedEntries->wipeOut();
delete pVisitedEntries;
}
}
virtual void lookupIfNecessary() {}
NSI_BINDING_VECTOR_T *next(
);
int finished();
virtual void rundown()
{
if (pCurrentHandle)
{
pCurrentHandle->rundown();
delete pCurrentHandle;
pCurrentHandle = NULL;
}
}
void setVisitedEntries(TSSLVisitedList *pVisited)
{
// this overrides the setting of this variable
// in the constructor
delete pVisitedEntries;
DBGOUT(TRACE, "Setting Visited Entries\n");
pVisitedEntries = pVisited;
// this also implies that this is a group handle in a larger
// group/profile lookup, hence does not own the visited
// entries list, which will therefore not be deleted in the dtor
fRootHandle = FALSE;
}
};
/*++
Class Definition:
CIndexLookupHandle
Abstract:
This is a specialization of the group handle class for Index lookup.
The only difference is an implementation of lookupIfNecessary().
--*/
class CIndexLookupHandle : public CGroupLookupHandle {
public:
CIndexLookupHandle(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
virtual void lookupIfNecessary();
};
/*++
Template Class Definition:
CCompleteHandle
Abstract:
The complete handle template implements the idea that a top level NS handle
typically is heterogeneous -- it contains info that is a) owned b) NonLocal
and c) just captured from the net. The behavior of such a handle is
independent of the nature of the data being looked up, hence the template.
--*/
template <class ItemType>
class CCompleteHandle : public CNSHandle<ItemType> {
/* these three handles are owned by this object and therefore
destroyed when it is deleted */
CNSHandle<ItemType> * pLocalHandle;
CNSHandle<ItemType> * pNonLocalHandle;
CNSHandle<ItemType> * pNetHandle;
BOOL fCacheIsValid;
public:
#if DBG
static ULONG ulHandleCount;
static ULONG ulHandleNo;
ULONG ulMyHandleNo;
#endif
ULONG netStatus() { return pNetHandle->getStatus(); }
CCompleteHandle(
CNSHandle<ItemType> * pLocal,
CNSHandle<ItemType> * pNonLocal,
CNSHandle<ItemType> * pNet,
ULONG ulCacheAge
)
{
#if DBG
ulHandleCount++;
ulHandleNo++;
ulMyHandleNo = ulHandleNo;
#endif
DBGOUT(MEM1, "CompleteHandle#" << ulMyHandleNo << " Created at"
<< CurrentTime() << "\n\n");
fCacheIsValid = FALSE;
pLocalHandle = pLocal;
pNonLocalHandle = pNonLocal;
pNetHandle = pNet;
setExpiryAge(ulCacheAge);
// By checking if there is any info at all, we force
// initialization of remote handles if necessary
finished();
}
~CCompleteHandle() {
DBGOUT(MEM1, "CompleteHandle#" << (ulHandleCount--,ulMyHandleNo) << " Destroyed at"
<< CurrentTime() << "\n\n");
rundown();
}
/* setExpiryAge on component handles should accomplish the needful */
virtual void lookupIfNecessary() {}
virtual void rundown();
virtual void setExpiryAge(
ULONG ulCacheAge
)
{
ulCacheMax = ulCacheAge;
if (pLocalHandle) pLocalHandle->setExpiryAge(ulCacheAge);
if (pNonLocalHandle) pNonLocalHandle->setExpiryAge(ulCacheAge);
if (pNetHandle) pNetHandle->setExpiryAge(ulCacheAge);
}
ItemType *next();
int finished();
};
#if DBG
template <class ItemType>
ULONG
CCompleteHandle<ItemType>::ulHandleCount = 0;
template <class ItemType>
ULONG
CCompleteHandle<ItemType>::ulHandleNo = 0;
#endif
template <class ItemType>
void
CCompleteHandle<ItemType>::rundown()
{
if (pLocalHandle) pLocalHandle->rundown();
if (pNonLocalHandle) pNonLocalHandle->rundown();
if (pNetHandle) pNetHandle->rundown();
if (pLocalHandle) delete pLocalHandle;
if (pNonLocalHandle) delete pNonLocalHandle;
if (pNetHandle) delete pNetHandle;
pLocalHandle = NULL;
pNonLocalHandle = NULL;
pNetHandle = NULL;
}
template <class ItemType>
ItemType *
CCompleteHandle<ItemType>::next()
{
DBGOUT(BROADCAST, "\n*****Entering CCompleteHandle**Next**\n");
if (pLocalHandle) {
if (!pLocalHandle->finished()) {
DBGOUT(BROADCAST, "From Local Entry\n");
return pLocalHandle->next();
}
else {
delete pLocalHandle;
pLocalHandle = NULL;
}
}
if (pNonLocalHandle) {
if (!pNonLocalHandle->finished()) {
DBGOUT(BROADCAST, "From NonLocal Entry\n");
fCacheIsValid = TRUE;
return pNonLocalHandle->next();
}
else {
delete pNonLocalHandle;
pNonLocalHandle = NULL;
}
}
// Go over the wire only if we do not have a valid cache..
if ((!fCacheIsValid) && (pNetHandle)) {
if (!pNetHandle->finished()) {
DBGOUT(BROADCAST, "From NetHandle Entry\n");
return pNetHandle->next();
}
else {
delete pNetHandle;
pNetHandle = NULL;
}
}
DBGOUT(BROADCAST, "Returning NULL\n");
return NULL;
}
template <class ItemType>
int
CCompleteHandle<ItemType>::finished()
{
return (pLocalHandle ? pLocalHandle->finished() : TRUE) &&
(pNonLocalHandle ? pNonLocalHandle->finished() : TRUE) &&
(pNetHandle ? pNetHandle->finished() : TRUE);
}
/*++
This is a wrapper class that wraps the CCompleteHandle and stores
the prev binding that was returned to the client in case of a locator-to-
locator lookup.
This is called only in I_ns_lookup api functions.
--*/
class CLocToLocCompleteHandle : public CContextHandle
{
CNSBinding *prevBinding;
public:
CCompleteHandle<NSI_BINDING_VECTOR_T> *pcompleteHandle;
CLocToLocCompleteHandle(
CCompleteHandle<NSI_BINDING_VECTOR_T> *pcompleteHandleFound)
:pcompleteHandle(pcompleteHandleFound)
{
prevBinding = NULL;
}
~CLocToLocCompleteHandle()
{
if (prevBinding)
delete prevBinding;
if (pcompleteHandle)
delete pcompleteHandle;
}
void StripObjectsFromAndCompress(
NSI_BINDING_VECTOR_P_T * BindingVectorOut);
void rundown()
{
DBGOUT(TRACE, "Called Rundown on LocToLoc Handle\n");
if (pcompleteHandle)
pcompleteHandle->rundown();
pcompleteHandle = NULL;
if (prevBinding)
delete prevBinding;
prevBinding = NULL;
}
};
/*++
Class Definition:
CInterfaceIndex
Abstract:
This class defines an entire interface index in the locator.
It is like a pseudo entry, but hasn't been formatted that way.
The form of the lookup method suggests it.
--*/
class Locator;
class CInterfaceIndex {
struct CInterfaceIndexEntry : public CGUID { // private class
TCSafeSkipList<CStringW> PossibleEntries;
CInterfaceIndexEntry(CGUID& guid) : CGUID(guid)
{}
~CInterfaceIndexEntry() {
PossibleEntries.wipeOut();
}
void insert(
CServerEntry * pSElocation) {
CStringW *psw = new CStringW(*pSElocation);
if (Duplicate == PossibleEntries.insert(psw))
delete psw;
}
void remove(CServerEntry * pSElocation) {
CStringW * deletedItem =
PossibleEntries.remove(pSElocation);
// the item had better be there!
// ASSERT(deletedItem, "Interface Index Corrupted\n");
}
};
CReadWriteSection rwLock;
TCSafeSkipList<CInterfaceIndexEntry> InterfaceEntries;
/* the null index contains all entries in EntryList */
CInterfaceIndexEntry *pNullIndex;
Locator *pMyLocator;
public:
CInterfaceIndex(
Locator *myL
)
{
CGUID nullGUID; // inits as null UUID thru default constructor
pNullIndex = new CInterfaceIndexEntry(nullGUID);
pMyLocator = myL;
}
~CInterfaceIndex() {
InterfaceEntries.wipeOut();
delete pNullIndex;
}
void insert(
CServerEntry * pSElocation,
CInterface * pInf);
void remove(
CServerEntry * pSElocation,
CInterface * pInf);
void removeServerEntry(CServerEntry *pSElocation);
TSLLEntryList * lookup(
CGUIDVersion * pGVInterface
);
};
CEntry *GetEntryFromDS(UNSIGNED32 EntryNameSyntax, STRING_T pszEntryName);
// in dsedit.cxx
/*++
Class Definition:
CDSNullLookupHandle
Abstract:
DS lookup handle. It is lazy and gets the data only when next is called.
Null Entry Lookup: All the server entries with the object uuid
will be enumerated and the interfaces will be looked at one by one for
the correct interface id.
Very similar to the group lookup.
--*/
class CDSNullLookupHandle : public CLookupHandle {
protected:
/* search parameters */
CGUIDVersion * pGVInterface;
CGUIDVersion * pGVTransferSyntax;
CGUID * pIDobject;
unsigned long ulVectorSize;
BOOL fUnusedHandle;
CDSQry * pDSQry;
BOOL fNotInitialized;
/* handle for the currently active entry */
CLookupHandle * pCurrentHandle;
void advanceCurrentHandle(); // look for next nonempty entry handle
virtual void initialize();
#if DBG
ULONG ulDSNullLookupHandleCount;
static ULONG ulDSNullLookupHandleNo;
ULONG ulHandleNo;
#endif
public:
virtual void rundown()
{
DBGOUT(TRACE,"CDSNullLookupHandle::rundown called for Handle#" << ulHandleNo << "\n\n");
if (pCurrentHandle)
{
pCurrentHandle->rundown();
delete pCurrentHandle;
pCurrentHandle = NULL;
}
fNotInitialized = TRUE;
}
CDSNullLookupHandle(
CGUIDVersion * pGVInterface,
CGUIDVersion * pGVTransferSyntax,
CGUID * pIDobject,
unsigned long ulVectorSize,
unsigned long ulCacheAge
);
~CDSNullLookupHandle()
{
rundown();
#if DBG
ulDSNullLookupHandleCount--;
#endif
delete pGVInterface;
delete pGVTransferSyntax;
delete pIDobject;
delete pDSQry;
}
NSI_BINDING_VECTOR_T *next();
int finished();
void lookupIfNecessary() {};
};
#pragma hdrstop
#endif // _OBJECTS_HXX_