mirror of https://github.com/lianthony/NT4.0
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.
1026 lines
23 KiB
1026 lines
23 KiB
/*++
|
|
|
|
Microsoft Windows NT RPC Name Service
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
brodcast.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the code for all mailslot activity relating to
|
|
binding handle queries-- both outgoing and incoming ones.
|
|
|
|
Things to improve in future revisions:
|
|
|
|
1. CBindingVector::msriList
|
|
|
|
2. formQueryPacket
|
|
|
|
Author:
|
|
|
|
Satish Thatte (SatishT) 08/15/95 Created all the code below except where
|
|
otherwise indicated.
|
|
|
|
--*/
|
|
|
|
|
|
#include <api.hxx>
|
|
#include <var.hxx>
|
|
#include <locquery.h>
|
|
|
|
/* NOTE: Compatibility Issue: see below for meaning of END_FLAG_SIZE */
|
|
|
|
const int END_FLAG_SIZE = 4;
|
|
|
|
|
|
/**************** Utilities for Broadcast **********************/
|
|
|
|
|
|
/* a little macro exclusively for use in UnmarshallBroadcastReplyItem */
|
|
|
|
#define unBufferIt(source) \
|
|
lBufferSize -= advance; \
|
|
if (lBufferSize < 0) { \
|
|
StatusCode = NSI_S_UNMARSHALL_UNSUCCESSFUL; \
|
|
return; \
|
|
} \
|
|
if (source) memcpy((char*) source, pcBuffer, advance); \
|
|
pcBuffer += advance;
|
|
|
|
|
|
void
|
|
UnmarshallBroadcastReplyItem(
|
|
TSSLEntryList *psslCache,
|
|
STRING_T szEntryDomain,
|
|
char * &pcBuffer,
|
|
long& lBufferSize,
|
|
ULONG& StatusCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unmarshall an item from the broadcast reply buffer. If a well-formed item
|
|
is found, the locator's cache and the temporary given cache (first argument)
|
|
is updated and the buffer size is decreased accordingly. A reply packet
|
|
contains the name of the replying locator's domain, which is used as the
|
|
domain of the entry unless otherwise specified in the name itself.
|
|
|
|
If the unmarshalling is unsuccessful, this is indicated in the status code returned.
|
|
|
|
Arguments:
|
|
|
|
psslCache - temporary cache for remote handle
|
|
|
|
szEntryDomain - domain of replying locator
|
|
|
|
pcBuffer - reply buffer
|
|
|
|
lBufferSize - reduced buffer size returned here
|
|
|
|
StatusCode - status of unmarshalling attempt returned here
|
|
|
|
Returned Status:
|
|
|
|
NSI_S_OK, NSI_OUT_OF_MEMORY, NSI_S_UNMARSHALL_UNSUCCESSFUL,
|
|
NSI_S_UNSUPPORTED_BUFFER_TYPE
|
|
|
|
Remarks:
|
|
|
|
The following function has "return"s inside a __try block. Since this whole code
|
|
is slated for removal after a couple of updates, I have left them in. They could
|
|
be easily replaced with "goto"s if necessary.
|
|
|
|
--*/
|
|
{
|
|
StatusCode = NSI_S_OK;
|
|
long advance;
|
|
RPC_SYNTAX_IDENTIFIER Interface;
|
|
RPC_SYNTAX_IDENTIFIER XferSyntax;
|
|
STRING_T binding;
|
|
STRING_T entryName = NULL;
|
|
|
|
advance = sizeof(fixed_part_of_reply);
|
|
fixed_part_of_reply fpr;
|
|
unBufferIt(&fpr);
|
|
|
|
if (fpr.type != MailslotServerEntryType) {
|
|
StatusCode = NSI_S_UNSUPPORTED_BUFFER_TYPE;
|
|
return;
|
|
}
|
|
|
|
Interface = fpr.Interface;
|
|
XferSyntax = fpr.XferSyntax;
|
|
|
|
advance = fpr.EntryNameLength * sizeof(WCHAR);
|
|
entryName = (WCHAR*) pcBuffer;
|
|
if (fpr.EntryNameLength != (wcslen(entryName) + 1)) {
|
|
StatusCode = NSI_S_UNMARSHALL_UNSUCCESSFUL;
|
|
return;
|
|
}
|
|
unBufferIt(NULL);
|
|
|
|
advance = sizeof(UNSIGNED32);
|
|
UNSIGNED32 objVectorSize;
|
|
unBufferIt(&objVectorSize);
|
|
|
|
|
|
GUID * guidVector = new GUID[objVectorSize];
|
|
|
|
NSI_UUID_VECTOR_T * pUuidVector = (NSI_UUID_VECTOR_T *)
|
|
new char [
|
|
sizeof(UNSIGNED32) +
|
|
sizeof(NSI_UUID_P_T) * objVectorSize
|
|
];
|
|
|
|
pUuidVector->count = objVectorSize;
|
|
|
|
advance = sizeof(void*); // this is a useless pointer part
|
|
lBufferSize -= advance; // therefore we don't unmarshall it
|
|
pcBuffer += advance; // we just account for its size
|
|
|
|
CStringW *pswEntry = NULL, *pswDomain = NULL;
|
|
CEntryName * penTempName = NULL;
|
|
|
|
__try{
|
|
|
|
advance = sizeof(GUID);
|
|
|
|
for (ULONG i = 0; i < objVectorSize; i++) {
|
|
pUuidVector->uuid[i] = &(guidVector[i]);
|
|
unBufferIt(&(guidVector[i]));
|
|
}
|
|
|
|
advance = fpr.BindingLength * sizeof(WCHAR);
|
|
binding = (WCHAR*) pcBuffer;
|
|
if (fpr.BindingLength != (wcslen(binding) + 1)) {
|
|
StatusCode = NSI_S_UNMARSHALL_UNSUCCESSFUL;
|
|
return;
|
|
}
|
|
unBufferIt(NULL);
|
|
|
|
/* first update the central cache and, if there is anything new,
|
|
also update the temporary cache in psslCache
|
|
*/
|
|
|
|
|
|
parseEntryName(entryName,pswDomain,pswEntry);
|
|
|
|
if (!pswDomain && szEntryDomain) // if name has no domain then use the
|
|
// domain of origin in forming name
|
|
|
|
penTempName = new CEntryName(szEntryDomain,*pswEntry);
|
|
|
|
else penTempName = new CEntryName(entryName);
|
|
|
|
myRpcLocator->UpdateCache(
|
|
*penTempName,
|
|
RPC_C_NS_SYNTAX_DCE,
|
|
Interface,
|
|
XferSyntax,
|
|
binding,
|
|
pUuidVector,
|
|
psslCache
|
|
);
|
|
}
|
|
__finally {
|
|
delete [] pUuidVector;
|
|
delete [] guidVector;
|
|
delete pswDomain;
|
|
delete pswEntry;
|
|
delete penTempName;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CBroadcastQueryPacket::subsumes(QueryPacket& NewQuery, ULONG tolerance) {
|
|
|
|
// too stale?
|
|
|
|
if (!isCurrent(tolerance)) return FALSE;
|
|
|
|
CStringW OtherEntry(NewQuery.EntryName);
|
|
|
|
// incompatible entry name involved?
|
|
|
|
if (!(swEntryName == OtherEntry) && (swEntryName.length() > 0))
|
|
return FALSE;
|
|
|
|
CGUID OtherObject(NewQuery.Object);
|
|
|
|
// incompatible object involved?
|
|
|
|
if (!(OtherObject == Object) && !Object.IsNil()) return FALSE;
|
|
|
|
CGUIDVersion OtherInterface(NewQuery.Interface);
|
|
CGUID myGUID(Interface.myIdAndVersion().SyntaxGUID);
|
|
|
|
// incompatible interface involved?
|
|
|
|
if (
|
|
!OtherInterface.isMatching(Interface,RPC_C_VERS_COMPATIBLE) &&
|
|
!myGUID.IsNil()
|
|
)
|
|
return FALSE;
|
|
|
|
// we ran the gauntlet successfully -- stop the broadcast!
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
void
|
|
formQueryPacket(
|
|
CEntryName * penEntryName,
|
|
CGUIDVersion * pGVInterface,
|
|
CGUID * pIDobject,
|
|
QueryPacket & NetRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Forms a query packet given the items in it.
|
|
|
|
Arguments:
|
|
|
|
penEntryName - (wrapped) entry name
|
|
|
|
pGVInterface - (wrapped) interface UUID and version
|
|
|
|
pIDobject - (wrapped) object UUID
|
|
|
|
NetRequest - The request packet is returned here
|
|
|
|
Remarks:
|
|
|
|
BUGBUG:
|
|
|
|
We used to perform some shenanigans with interface and object settings
|
|
in the QueryPacket to allow us to correctly report NSI_S_ENTRY_NOT_FOUND
|
|
when appropriate. Specifically, using wildcards for interface and object
|
|
if the entry name was non null so as to gather all information about the
|
|
specific entry from the net.
|
|
|
|
In order to interoperate with the old locator, these shenanigans have
|
|
been suspended, and we will currently return NSI_S_ENTRY_NOT_FOUND
|
|
spuriously when no information is received from the net in response to
|
|
a specific rather than a wildcard query, just like the old locator
|
|
(so that the old tests pass when they expect NSI_S_ENTRY_NOT_FOUND !!).
|
|
|
|
The problem with the old locator is that it carefully avoids sending
|
|
duplicate binding handles, so if a null interface is given in
|
|
the broadcast query, it naturally assumes that we don't care about the
|
|
interface, and may omit info about some interfaces unless they have
|
|
distinct binding handles associated with them.
|
|
|
|
--*/
|
|
{
|
|
|
|
memset(&(NetRequest.Object),0,sizeof(NetRequest.Object));
|
|
memset(&(NetRequest.Interface),0,sizeof(NetRequest.Interface));
|
|
|
|
if (penEntryName) // specific entry - we used to leave wildcards for interface and object
|
|
wcscpy(NetRequest.EntryName,*penEntryName);
|
|
|
|
else // otherwise, use real interface and object if given
|
|
memset(&(NetRequest.EntryName),0,sizeof(WCHAR)*MAX_ENTRY_NAME_LENGTH);
|
|
|
|
// NOTE: compatibility removal: the following two lines were conditional
|
|
// on the else before the "shenanigans" were eliminated
|
|
|
|
if (pIDobject) NetRequest.Object = pIDobject->myGUID();
|
|
if (pGVInterface) NetRequest.Interface = *pGVInterface;
|
|
}
|
|
|
|
|
|
TSSLEntryList *
|
|
getBroadcastResults(
|
|
ULONG cacheTolerance,
|
|
CEntryName * penEntryName,
|
|
CGUIDVersion * pGVInterface,
|
|
CGUID * pIDobject,
|
|
ULONG & StatusCode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Broadcasts for the requested binding handles.
|
|
|
|
Arguments:
|
|
|
|
cacheTolerance - the staleness tolerance associated with this request,
|
|
used in deciding whether to broadcast at all
|
|
|
|
penEntryName - (wrapped) entry name
|
|
|
|
pGVInterface - (wrapped) interface UUID and version
|
|
|
|
pIDobject - (wrapped) object UUID
|
|
|
|
StatusCode - The status of the broadcast attempt is returned here
|
|
|
|
Returns:
|
|
|
|
A temporary cache of entries containing the new information.
|
|
|
|
Remarks:
|
|
|
|
A broadcast is made only if a subsuming broadcast has not been made within
|
|
the staleness limit specified by the parameter cacheTolerance. Only one
|
|
broadcast is allowed at a time, since there is only one mailslot for replies.
|
|
|
|
--*/
|
|
{
|
|
char * pcBuffer;
|
|
ULONG waitCur = INITIAL_MAILSLOT_READ_WAIT; // current wait time for replies
|
|
STRING_T szEntryDomain;
|
|
|
|
READ_MAIL_SLOT *hMailslotForReplies = myRpcLocator->hMailslotForReplies;
|
|
long cbRead;
|
|
|
|
QueryReply NetReply;
|
|
|
|
if (!hMailslotForReplies) {
|
|
StatusCode = NSI_S_ENTRY_NOT_FOUND;
|
|
return NULL;
|
|
}
|
|
|
|
QueryPacket NetRequest;
|
|
|
|
wcscpy(NetRequest.WkstaName, TEXT("\\\\"));
|
|
wcscpy(NetRequest.WkstaName + 2, *myRpcLocator->getComputerName());
|
|
|
|
formQueryPacket(penEntryName,pGVInterface,pIDobject,NetRequest);
|
|
|
|
// now get this broadcast cleared -- make sure it is not redundant
|
|
|
|
if (!myRpcLocator->broadcastCleared(NetRequest,cacheTolerance))
|
|
{
|
|
if (penEntryName)
|
|
|
|
DBGOUT(BROADCAST, "\nBroadcast request denied for " << *penEntryName << "\n"
|
|
<< "Interface = " << &NetRequest.Interface.SyntaxGUID << "\n"
|
|
<< "Object = " << &NetRequest.Object << "\n\n");
|
|
|
|
else DBGOUT(BROADCAST, "\nBroadcast request denied for NULL entry\n"
|
|
<< "Interface = " << &NetRequest.Interface.SyntaxGUID << "\n"
|
|
<< "Object = " << &NetRequest.Object << "\n\n");
|
|
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if (penEntryName)
|
|
|
|
DBGOUT(BROADCAST, "\nI am broadcasting for " << *penEntryName << "\n"
|
|
<< "Interface = " << &NetRequest.Interface.SyntaxGUID << "\n"
|
|
<< "Object = " << &NetRequest.Object << "\n\n");
|
|
|
|
else DBGOUT(BROADCAST, "\nI am broadcasting for NULL entry\n"
|
|
<< "Interface = " << &NetRequest.Interface.SyntaxGUID << "\n"
|
|
<< "Object = " << &NetRequest.Object << "\n\n");
|
|
|
|
myRpcLocator->markBroadcast(NetRequest);
|
|
}
|
|
|
|
|
|
// szDomain should be either NULL or a plain Domain name
|
|
|
|
STRING_T szDomainParam;
|
|
|
|
CStringW *pswDomain = penEntryName ? penEntryName->getDomainName() : NULL;
|
|
|
|
if (pswDomain)
|
|
szDomainParam = catenate(TEXT("\\\\"),*pswDomain);
|
|
else szDomainParam = TEXT("\\\\*");
|
|
|
|
TSSLEntryList *psslCache = new TSSLEntryList;
|
|
|
|
StatusCode = NSI_S_OK;
|
|
|
|
__try {
|
|
|
|
csBindingBroadcastGuard.Enter(); // only one broadcast at a time
|
|
|
|
WRITE_MAIL_SLOT MSquery(szDomainParam, PMAILNAME_S);
|
|
|
|
MSquery.Write((char *) &NetRequest, sizeof(NetRequest));
|
|
|
|
// now loop waiting for responses from other RPC servers
|
|
|
|
while (cbRead = hMailslotForReplies->Read((char *) &NetReply,
|
|
sizeof(NetReply),
|
|
waitCur
|
|
)
|
|
)
|
|
{
|
|
pcBuffer = NetReply.Buffer;
|
|
szEntryDomain = (_wcsicmp(
|
|
*myRpcLocator->getDomainName(),
|
|
NetReply.Domain
|
|
)
|
|
== 0
|
|
)? NULL: NetReply.Domain;
|
|
|
|
while (!StatusCode) {
|
|
|
|
UnmarshallBroadcastReplyItem(
|
|
psslCache,
|
|
szEntryDomain,
|
|
pcBuffer,
|
|
cbRead,
|
|
StatusCode
|
|
);
|
|
}
|
|
|
|
StatusCode = NSI_S_OK;
|
|
|
|
// halve the wait period everytime you get a response from the net
|
|
|
|
waitCur >>= 1;
|
|
}
|
|
|
|
csBindingBroadcastGuard.Leave();
|
|
}
|
|
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
csBindingBroadcastGuard.Leave();
|
|
StatusCode = GetExceptionCode();
|
|
psslCache->wipeOut();
|
|
delete psslCache;
|
|
psslCache = NULL;
|
|
if (pswDomain) delete [] szDomainParam;
|
|
return NULL;
|
|
}
|
|
|
|
if (pswDomain) delete [] szDomainParam;
|
|
|
|
if (psslCache->size() == 0) {
|
|
delete psslCache;
|
|
psslCache = NULL;
|
|
}
|
|
|
|
return psslCache;
|
|
}
|
|
|
|
|
|
/**************** Methods related to MailSlotReplyItem ********************/
|
|
|
|
/* a little macro exclusively for use in CMailSlotReplyItem::Marshall */
|
|
|
|
#define bufferIt(source) \
|
|
lBufferSize -= advance; \
|
|
if (lBufferSize < 0) return 0; \
|
|
memcpy(pcBuffer, (char*) source, advance); \
|
|
pcBuffer += advance;
|
|
|
|
|
|
DWORD
|
|
CMailSlotReplyItem::Marshall(
|
|
char * pcBuffer,
|
|
long lBufferSize
|
|
)
|
|
|
|
/*++
|
|
Method Description:
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwOriginalBufferSize = lBufferSize;
|
|
|
|
fixed_part_of_reply fpr;
|
|
|
|
fpr.type = MailslotServerEntryType;
|
|
|
|
fpr.Interface = Interface;
|
|
fpr.XferSyntax = XferSyntax;
|
|
|
|
fpr.BindingLength = wcslen(binding)+ 1;
|
|
fpr.EntryNameLength = wcslen(entryName) + 1;
|
|
|
|
long advance;
|
|
|
|
advance = sizeof(fixed_part_of_reply);
|
|
bufferIt(&fpr);
|
|
|
|
advance = fpr.EntryNameLength * sizeof(WCHAR);
|
|
bufferIt(entryName);
|
|
|
|
advance = sizeof(long);
|
|
long objListSize = pObjectList->size();
|
|
bufferIt(&objListSize);
|
|
|
|
advance = sizeof(void*); // this is a useless pointer part
|
|
lBufferSize -= advance; // therefore we don't marshall it
|
|
pcBuffer += advance; // we just account for its size
|
|
|
|
TCSafeSkipListIterator<CGUID> objIter(*pObjectList);
|
|
advance = sizeof(GUID);
|
|
|
|
for (CGUID *obj =objIter.next(); obj; obj =objIter.next()) {
|
|
GUID rep = obj->myGUID();
|
|
bufferIt(&rep);
|
|
}
|
|
|
|
advance = fpr.BindingLength * sizeof(WCHAR);
|
|
bufferIt(binding);
|
|
|
|
return dwOriginalBufferSize - lBufferSize;
|
|
}
|
|
|
|
|
|
TMSRILinkList *
|
|
CBindingVector::msriList(
|
|
CInterface *pIf,
|
|
TCSafeSkipList<CGUID>* psslObjList
|
|
)
|
|
|
|
/*++
|
|
Method Description:
|
|
|
|
We combine every relevant object in the server entry with every basic
|
|
binding string although that seems ridiculous. This is the way the old
|
|
locator expects us to behave as far as I can tell.
|
|
|
|
--*/
|
|
|
|
{
|
|
CMailSlotReplyItem *pmsrl;
|
|
TMSRILinkList *pmsrill = new TMSRILinkList;
|
|
|
|
TCSafeSkipListIterator<CStringW> bindingIter(*this);
|
|
|
|
for (CStringW * psw = bindingIter.next(); psw; psw = bindingIter.next())
|
|
|
|
{
|
|
pmsrl = new CMailSlotReplyItem;
|
|
|
|
pmsrl->binding = *psw;
|
|
pmsrl->pObjectList = psslObjList;
|
|
pmsrl->Interface = pIf->myIdAndVersion();
|
|
pmsrl->XferSyntax = pIf->xferSyntaxIdAndVersion();
|
|
pmsrl->entryName = pMyEntry->getCurrentName();
|
|
|
|
pmsrill->insert(pmsrl);
|
|
}
|
|
|
|
return pmsrill;
|
|
}
|
|
|
|
|
|
/********** CBroadcastLookupHandle Methods ****************/
|
|
|
|
CBroadcastLookupHandle::CBroadcastLookupHandle(
|
|
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
|
|
)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void
|
|
CBroadcastLookupHandle::initialize()
|
|
{
|
|
|
|
StatusCode = NSI_S_OK;
|
|
|
|
psslNewCache = getBroadcastResults(
|
|
ulCacheMax,
|
|
penEntryName,
|
|
pgvInterface,
|
|
pidObject,
|
|
StatusCode
|
|
);
|
|
|
|
if (!psslNewCache) plhFetched = NULL;
|
|
|
|
else {
|
|
|
|
TSSLEntryListIterator *pCacheIter = new TSSLEntryListIterator(*psslNewCache);
|
|
|
|
plhFetched = new CGroupLookupHandle(
|
|
pCacheIter,
|
|
pgvInterface,
|
|
pgvTransferSyntax,
|
|
pidObject,
|
|
ulVS,
|
|
ulCacheMax
|
|
);
|
|
}
|
|
|
|
|
|
if (penEntryName && !plhFetched) // we looked for a specific entry
|
|
StatusCode = NSI_S_ENTRY_NO_NEW_INFO; // by name but found nothing new,
|
|
// possibly because the broadcast
|
|
// was redundant and was not made
|
|
|
|
ulCreationTime = CurrentTime();
|
|
fNotInitialized = FALSE;
|
|
}
|
|
|
|
|
|
/****************** CBroadcastObjectInqHandle Methods *******************/
|
|
|
|
CBroadcastObjectInqHandle::CBroadcastObjectInqHandle(
|
|
STRING_T szEntryName,
|
|
ULONG ulCacheAge
|
|
)
|
|
: CRemoteObjectInqHandle(szEntryName,ulCacheAge)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
CBroadcastObjectInqHandle::initialize()
|
|
{
|
|
StatusCode = NSI_S_OK;
|
|
|
|
TSSLEntryList *psslNewCache = getBroadcastResults(
|
|
ulCacheMax,
|
|
penEntryName,
|
|
NULL,
|
|
NULL,
|
|
StatusCode
|
|
);
|
|
|
|
if (!psslNewCache || (psslNewCache->size() == 0)) {
|
|
pUuidVector = NULL;
|
|
return;
|
|
}
|
|
|
|
CEntry *pEntry = psslNewCache->pop();
|
|
|
|
psslNewCache->wipeOut();
|
|
delete psslNewCache;
|
|
|
|
pUuidVector = getVector(pEntry->objectInquiry(ulCacheMax));
|
|
delete pEntry;
|
|
|
|
ulCreationTime = CurrentTime();
|
|
fNotInitialized = FALSE;
|
|
}
|
|
|
|
|
|
/************ Methods for CServerMailSlotReplyHandle *************/
|
|
|
|
|
|
CServerMailSlotReplyHandle::CServerMailSlotReplyHandle(
|
|
TMSRILinkList * pmsrill
|
|
)
|
|
{
|
|
pmsriIterator = new TMSRILinkListIterator(*pmsrill);
|
|
|
|
delete pmsrill; // see CServerLookupHandle::CServerLookupHandle above
|
|
}
|
|
|
|
|
|
CServerMailSlotReplyHandle::~CServerMailSlotReplyHandle()
|
|
{
|
|
for ( // run down the remaining items in the handle
|
|
CMailSlotReplyItem* pmsri = pmsriIterator->next();
|
|
pmsri;
|
|
pmsri = pmsriIterator->next()
|
|
)
|
|
{
|
|
delete pmsri;
|
|
}
|
|
|
|
delete pmsriIterator;
|
|
}
|
|
|
|
|
|
|
|
/************ Methods for CIndexMailSlotReplyHandle *************/
|
|
|
|
|
|
void
|
|
CIndexMailSlotReplyHandle::advanceCurrentHandle()
|
|
{
|
|
delete pCurrentHandle;
|
|
pCurrentHandle = NULL;
|
|
|
|
CEntry *pCurEntry;
|
|
|
|
while (!pEIterator->finished()) {
|
|
|
|
pCurEntry = pEIterator->next();
|
|
if (pCurEntry->isCacheType()) continue;
|
|
|
|
pCurrentHandle = pCurEntry->MailSlotLookup(
|
|
pGVInterface,
|
|
pIDobject
|
|
);
|
|
|
|
if (pCurrentHandle && !pCurrentHandle->finished()) break;
|
|
}
|
|
}
|
|
|
|
|
|
CIndexMailSlotReplyHandle::CIndexMailSlotReplyHandle(
|
|
CGUIDVersion * pGVInf,
|
|
CGUID * pIDobj,
|
|
TEntryIterator * pEI
|
|
)
|
|
{
|
|
pEIterator = pEI;
|
|
pGVInterface = pGVInf;
|
|
pIDobject = pIDobj;
|
|
pCurrentHandle = NULL;
|
|
|
|
advanceCurrentHandle();
|
|
}
|
|
|
|
|
|
CMailSlotReplyItem *
|
|
CIndexMailSlotReplyHandle::next()
|
|
{
|
|
if (pCurrentHandle && pCurrentHandle->finished())
|
|
advanceCurrentHandle();
|
|
|
|
if (!pCurrentHandle) return NULL; // no more entries
|
|
else return pCurrentHandle->next();
|
|
}
|
|
|
|
int
|
|
CIndexMailSlotReplyHandle::finished()
|
|
{
|
|
if (pCurrentHandle && pCurrentHandle->finished())
|
|
advanceCurrentHandle();
|
|
|
|
if (!pCurrentHandle) return TRUE; // no more entries
|
|
else return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/************ MailSlotLookup Methods *************/
|
|
|
|
|
|
CMailSlotReplyHandle *
|
|
CServerEntry::MailSlotLookup(
|
|
CGUIDVersion * pGVInterface,
|
|
CGUID * pIDobject
|
|
)
|
|
|
|
|
|
/*++
|
|
Method Description:
|
|
|
|
--*/
|
|
|
|
{
|
|
TCSafeSkipListIterator<CInterface> IfIter(InterfaceList);
|
|
|
|
TMSRILinkList *pmsrill = new TMSRILinkList;
|
|
|
|
for (CInterface *pIf = IfIter.next(); pIf != NULL; pIf = IfIter.next())
|
|
if (pIf->isCompatibleWith(pGVInterface,NULL)
|
|
)
|
|
{
|
|
TMSRILinkList *pmsrillTemp
|
|
= pIf->pBVhandles->msriList(pIf,&ObjectList);
|
|
|
|
pmsrill->catenate(*pmsrillTemp);
|
|
|
|
delete pmsrillTemp;
|
|
}
|
|
|
|
return new CServerMailSlotReplyHandle(
|
|
pmsrill
|
|
);
|
|
}
|
|
|
|
|
|
CMailSlotReplyHandle *
|
|
CFullServerEntry::MailSlotLookup(
|
|
CGUIDVersion * pGVInterface,
|
|
CGUID * pIDobject
|
|
)
|
|
{
|
|
if (pLocalEntry) return pLocalEntry->MailSlotLookup(
|
|
pGVInterface,
|
|
pIDobject
|
|
);
|
|
else return NULL;
|
|
}
|
|
|
|
|
|
/************** Thread definition for replying to broadcasts ***************/
|
|
|
|
|
|
#define cleanup() \
|
|
delete plhQuery; \
|
|
delete pGVinterface; \
|
|
delete pIDobject; \
|
|
delete pEntryName;
|
|
|
|
void
|
|
QueryProcess(void*)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This thread creates a mailslot which listens for requests for
|
|
RPC servers of a given interface GID. It then uses LookUp to
|
|
build a response list. It then replies via a mailslot to the
|
|
requesting machine.
|
|
|
|
--*/
|
|
{
|
|
QueryReply NetReply;
|
|
QueryPacket NetQuery;
|
|
|
|
DWORD dwMailSize, dwBufferUsed;
|
|
|
|
// create both a server (s) side mailslot
|
|
|
|
READ_MAIL_SLOT *hMailslotForQueries;
|
|
|
|
__try{
|
|
hMailslotForQueries = new READ_MAIL_SLOT(PMAILNAME_S, sizeof(QueryPacket));
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER) {
|
|
ExitThread(NSI_S_MAILSLOT_ERROR);
|
|
}
|
|
|
|
wcscpy(NetReply.Domain, *myRpcLocator->getDomainName());
|
|
|
|
while (1) {
|
|
|
|
CMailSlotReplyHandle * plhQuery = NULL;
|
|
CGUIDVersion * pGVinterface = NULL;
|
|
CGUID * pIDobject = NULL;
|
|
CEntry * pEntry = NULL;
|
|
|
|
RPC_STATUS status = NSI_S_OK;
|
|
|
|
dwMailSize = hMailslotForQueries->Read(
|
|
(char *) &NetQuery,
|
|
sizeof(QueryPacket),
|
|
MAILSLOT_WAIT_FOREVER
|
|
);
|
|
|
|
if (dwMailSize != sizeof(QueryPacket))
|
|
continue; // strange query, ignore it
|
|
|
|
// ignore messages to self, sending a request on a mailslot
|
|
// by a NetLookUp request will be delivered to the local slot too.
|
|
// The pointer arithmetic skips over the initial "\\" in the name
|
|
|
|
if (myRpcLocator->IsSelf(NetQuery.WkstaName+2)) continue;
|
|
|
|
DBGOUT(BROADCAST, "\nReceived broadcast request from " << NetQuery.WkstaName << "\n\n");
|
|
|
|
// OK looks like a genuine query -- if we are in a workgroup, rememeber
|
|
// the broadcaster as a potential master
|
|
|
|
if (myRpcLocator->IsInWorkgroup()) myRpcLocator->addMaster((NetQuery.WkstaName)+2);
|
|
|
|
pGVinterface = UuidIsNil(&NetQuery.Interface.SyntaxGUID,&status) ? NULL :
|
|
new CGUIDVersion(NetQuery.Interface);
|
|
|
|
pIDobject = UuidIsNil(&NetQuery.Object,&status) ? NULL :
|
|
new CGUID(NetQuery.Object);
|
|
|
|
// Variable used to make sure the entry name is well formed and local
|
|
|
|
CEntryName *pEntryName = NULL;
|
|
|
|
// This global reader block is needed because a lot of the info in the
|
|
// MSRIs is "borrowed" from regular entries, i.e., not copied. Thus, an
|
|
// unexport in a separate thread can have unfortunate consequences.
|
|
|
|
CriticalReader me(rwEntryGuard);
|
|
|
|
if (NetQuery.EntryName[0] == 0) { // use default entry
|
|
|
|
plhQuery = new CIndexMailSlotReplyHandle(
|
|
pGVinterface,
|
|
pIDobject,
|
|
myRpcLocator->IndexLookup(pGVinterface)
|
|
);
|
|
|
|
if (!plhQuery) {
|
|
cleanup(); // ignore the query
|
|
continue; // if nothing to report
|
|
}
|
|
}
|
|
|
|
else {
|
|
|
|
__try {
|
|
pEntryName = new CEntryName(NetQuery.EntryName);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
cleanup(); // ignore the query
|
|
continue; // if there is any problem
|
|
}
|
|
|
|
|
|
if (!pEntryName->isLocal()) {
|
|
cleanup(); // ignore the query
|
|
continue; // if entry not in our domain
|
|
}
|
|
|
|
pEntry = myRpcLocator->findEntry(pEntryName);
|
|
|
|
if (!pEntry) {
|
|
cleanup(); // ignore the query
|
|
continue; // if entry not found
|
|
}
|
|
|
|
else plhQuery = pEntry->MailSlotLookup(
|
|
pGVinterface,
|
|
pIDobject
|
|
);
|
|
|
|
if (!plhQuery) {
|
|
cleanup(); // ignore the query
|
|
continue; // if nothing to report
|
|
}
|
|
|
|
}
|
|
|
|
WRITE_MAIL_SLOT MSReply(NetQuery.WkstaName, PMAILNAME_C);
|
|
|
|
char *pcBuffer = NetReply.Buffer;
|
|
|
|
/* we must take care of the possibility that an item is fetched but
|
|
cannot be marshalled because the buffer is full -- we have to
|
|
retry marshalling it in the next cycle
|
|
*/
|
|
|
|
CMailSlotReplyItem * pmsriNext = NULL;
|
|
|
|
pmsriNext = plhQuery->next();
|
|
|
|
while (pmsriNext) {
|
|
|
|
int BufferNotFull = TRUE;
|
|
dwBufferUsed = 0;
|
|
|
|
while (BufferNotFull && pmsriNext) {
|
|
|
|
/* NOTE: Compatibility Issue: The +END_FLAG_SIZE below reserves space for
|
|
the 4-byte 0 flag required by the old locator at the end of the buffer.
|
|
*/
|
|
|
|
DWORD dwBytesWritten =
|
|
pmsriNext->Marshall(
|
|
pcBuffer+dwBufferUsed,
|
|
NET_REPLY_BUFFER_SIZE-(dwBufferUsed+END_FLAG_SIZE)
|
|
);
|
|
|
|
if (dwBytesWritten) {
|
|
dwBufferUsed += dwBytesWritten;
|
|
delete pmsriNext;
|
|
pmsriNext = plhQuery->next(); // only if marshalling was successful
|
|
}
|
|
|
|
else BufferNotFull = FALSE;
|
|
|
|
}
|
|
|
|
/* NOTE: Compatibility Issue:
|
|
|
|
The old locator does not use the count of bytes read to decide when
|
|
to stop unmarshalling a mailslot reply -- instead it uses the 0 flag
|
|
after the last marshalled entry for that purpose, so for compatibility
|
|
reasons we must do the needful.
|
|
*/
|
|
|
|
memset(pcBuffer+dwBufferUsed,0,END_FLAG_SIZE);
|
|
|
|
MSReply.Write(
|
|
(char*) &NetReply,
|
|
dwBufferUsed + MAX_DOMAIN_NAME_LENGTH * sizeof(WCHAR) + END_FLAG_SIZE
|
|
);
|
|
}
|
|
|
|
cleanup();
|
|
}
|
|
}
|
|
|