Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2131 lines
41 KiB

/*++
Microsoft Windows NT RPC Name Service
Copyright (c) 1995 Microsoft Corporation
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.
--*/
/* BUGBUG: 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_
#define _OBJECTS_
#include <memory.h>
#include <globals.hxx>
#include <locquery.h>
class CGUID;
class CInterface;
struct CBVWrapper;
class CServerEntry;
class CCacheServerEntry;
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,
CacheServerEntryType,
FullServerEntryType
};
/*++
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() {} // 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();
// BUGBUG: should there be a destructor as a matter of principle?
};
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 : private TCSafeSkipList<CStringW>
{
CServerEntry *pMyEntry; // the entry this belongs to
public:
CBindingVector(NSI_SERVER_BINDING_VECTOR_T*, CServerEntry*);
~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);
}
TMSRILinkList *msriList(
CInterface *pIf,
TCSafeSkipList<CGUID>* psslObjList
);
};
/*++
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:
CGUIDVersion transferSyntax;
CBindingVector *pBVhandles;
int mergeHandles(NSI_SERVER_BINDING_VECTOR_T* pHandles) {
return pBVhandles->merge(pHandles);
}
public:
CInterface(
NSI_INTERFACE_ID_T * lpInf,
NSI_SERVER_BINDING_VECTOR_T *BindingVector,
CServerEntry *pMyEntry
);
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;
}
};
/*++
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;
public:
CEntryName(CONST_STRING_T fullName); // disassembling constructor
CEntryName( // assembling constructor
CONST_STRING_T domainName,
CONST_STRING_T entryName
);
virtual ~CEntryName(); // base class destructor should be virtual
CStringW* getDomainName()
{
return pswDomainName;
}
CStringW* getEntryName()
{
return pswEntryName;
}
void changeToLocalName()
{
delete pswDomainName;
pswDomainName = NULL;
delete [] pszVal;
pszVal = catenate(RelativePrefix,*pswEntryName);
}
STRING_T copyGlobalName();
STRING_T copyCurrentName()
{
return copyString(getCurrentName());
}
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();
};
/*++
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 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();
}
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 cached 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:
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)
{}
virtual ~CEntry() {}
EntryType getType() { return type; }
BOOL isCacheType() {
switch (type) {
case CacheServerEntryType: 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 CCacheEntryMixin 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;
};
typedef TCGuardedSkipList<CEntry> 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
cached 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;
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
*/
{
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:
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:
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() { // cache 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 removeInterfaces(
NSI_IF_ID_P_T Interface,
UNSIGNED32 VersOption,
CInterfaceIndex *
);
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
);
};
/*++
Class Definition:
CCacheServerEntry
Abstract:
A variation on CServerEntry with modifications to reflect the fact that the
info is cached 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 CCacheServerEntry : public CServerEntry {
ULONG ulCacheTime;
int fHasCachedInfo;
public:
virtual BOOL isCurrent(ULONG ulTolerance);
CCacheServerEntry(
CONST_STRING_T pszStr
)
: CServerEntry(pszStr,CacheServerEntryType)
{
fHasCachedInfo = FALSE;
ulCacheTime = 0;
}
virtual void flush()
{
CServerEntry::flush();
CriticalWriter me(rwCacheEntryGuard);
DBGOUT(OBJECT, "\nFlushing CCacheServerEntry\n");
DBGOUT(OBJECT, "EntryName = " << getCurrentName() << WNL);
DBGOUT(OBJECT, "This entry has a ulCacheTime = " << ulCacheTime << "\n\n");
fHasCachedInfo = FALSE;
}
int addObjects(NSI_UUID_VECTOR_P_T ObjectVector) {
{
CriticalWriter me(rwCacheEntryGuard);
if (!fHasCachedInfo) {
ulCacheTime = CurrentTime();
fHasCachedInfo = 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(rwCacheEntryGuard);
if (!fHasCachedInfo) {
ulCacheTime = CurrentTime();
fHasCachedInfo = 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 cached 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 cached 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
)
// Cached 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 cached
remote handles and partly locally exported handles. This is a
temporary situation until we have a persistent global database.
Therefore this struct does the minimal necessary to tide us over
until then. In particular, it is not a real server entry, but
exposes two kinds of server entries within itself.
--*/
class CFullServerEntry : public CEntry {
BOOL fNetLookupDone;
void flushCacheIfNecessary(ULONG ulTolerance);
CServerEntry *pLocalEntry;
CCacheServerEntry *pCachedEntry;
public:
CServerEntry *getLocal() {
CriticalReader me(rwFullEntryGuard);
return pLocalEntry;
}
CCacheServerEntry *getCache() {
CriticalReader me(rwFullEntryGuard);
return pCachedEntry;
}
CFullServerEntry(
CONST_STRING_T pszName
)
:CEntry(
pszName,
FullServerEntryType
)
{
pLocalEntry = new CServerEntry(pszName);
pCachedEntry = new CCacheServerEntry(pszName);
fNetLookupDone = FALSE;
}
virtual ~CFullServerEntry() {
delete pLocalEntry;
delete pCachedEntry;
}
virtual BOOL isEmpty() {
CriticalReader me(rwFullEntryGuard);
return pLocalEntry->isEmpty() && pCachedEntry->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:
CCacheServerObjectInqHandle
Abstract:
This is the object inquiry handle class for cached server entries.
The only difference from a local CServerObjectInqHandle is
the functionality added by CRemoteObjectInqHandle.
--*/
class CCacheServerObjectInqHandle : public CRemoteObjectInqHandle {
void initialize();
public:
CCacheServerObjectInqHandle(
STRING_T pszName,
ULONG ulCacheAge
);
};
/*++
Class Definition:
CGroupEntry
Abstract:
A stub for future extension.
--*/
class CGroupEntry : public CEntry {
protected:
TCSafeSkipList<CStringW> GroupList;
public:
CGroupEntry(const STRING_T pszStr)
: CEntry(pszStr, GroupEntryType) {}
};
/*++
Class Definition:
CProfileEntry
Abstract:
A stub for future extension.
--*/
class CProfileEntry : public CEntry {
public:
CProfileEntry(const STRING_T pszStr)
: CEntry(pszStr, ProfileEntryType) {}
};
/*++
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() {
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:
CCacheServerLookupHandle
Abstract:
This is the lookup handle class for cached server entries.
The only difference from a local CServerLookupHandle is
the functionality added by CRemoteLookupHandle.
--*/
class CCacheServerLookupHandle : public CRemoteLookupHandle {
void initialize();
public:
CCacheServerLookupHandle(
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;
/* Iterator for entries in the group -- please use a guarded kind! */
TEntryIterator *pEIterator;
/* handle for the currently active entry */
CLookupHandle * pCurrentHandle;
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;
}
virtual void lookupIfNecessary() {}
NSI_BINDING_VECTOR_T *next(
);
int finished();
virtual void rundown()
{
if (pCurrentHandle)
{
pCurrentHandle->rundown();
delete pCurrentHandle;
pCurrentHandle = NULL;
}
}
};
/*++
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) cached
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> * pCacheHandle;
CNSHandle<ItemType> * pNetHandle;
public:
#if DBG
static ULONG ulHandleCount;
static ULONG ulHandleNo;
ULONG ulMyHandleNo;
#endif
ULONG netStatus() { return pNetHandle->getStatus(); }
CCompleteHandle(
CNSHandle<ItemType> * pLocal,
CNSHandle<ItemType> * pCache,
CNSHandle<ItemType> * pNet,
ULONG ulCacheAge
)
{
#if DBG
ulHandleCount++;
ulHandleNo++;
ulMyHandleNo = ulHandleNo;
#endif
DBGOUT(MEM1, "CompleteHandle#" << ulMyHandleNo << " Created at"
<< CurrentTime() << "\n\n");
pLocalHandle = pLocal;
pCacheHandle = pCache;
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 (pCacheHandle) pCacheHandle->setExpiryAge(ulCacheAge);
if (pNetHandle) pNetHandle->setExpiryAge(ulCacheAge);
}
ItemType *next();
int finished();
};
template <class ItemType>
ULONG
CCompleteHandle<ItemType>::ulHandleCount = 0;
template <class ItemType>
ULONG
CCompleteHandle<ItemType>::ulHandleNo = 0;
template <class ItemType>
void
CCompleteHandle<ItemType>::rundown()
{
if (pLocalHandle) pLocalHandle->rundown();
if (pCacheHandle) pCacheHandle->rundown();
if (pNetHandle) pNetHandle->rundown();
delete pLocalHandle;
delete pCacheHandle;
delete pNetHandle;
pLocalHandle = NULL;
pCacheHandle = NULL;
pNetHandle = NULL;
}
template <class ItemType>
ItemType *
CCompleteHandle<ItemType>::next()
{
if (pLocalHandle)
if (!pLocalHandle->finished())
return pLocalHandle->next();
else {
delete pLocalHandle;
pLocalHandle = NULL;
}
if (pCacheHandle)
if (!pCacheHandle->finished())
return pCacheHandle->next();
else {
delete pCacheHandle;
pCacheHandle = NULL;
}
if (pNetHandle)
if (!pNetHandle->finished())
return pNetHandle->next();
else {
delete pNetHandle;
pNetHandle = NULL;
}
return NULL;
}
template <class ItemType>
int
CCompleteHandle<ItemType>::finished()
{
return (pLocalHandle ? pLocalHandle->finished() : TRUE) &&
(pCacheHandle ? pCacheHandle->finished() : TRUE) &&
(pNetHandle ? pNetHandle->finished() : TRUE);
}
/*++
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);
TSLLEntryList * lookup(
CGUIDVersion * pGVInterface
);
};
#endif // _OBJECTS_