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.
1213 lines
27 KiB
1213 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cache.cxx
|
|
|
|
Abstract:
|
|
|
|
This module deals with inter locator communication. Locators will
|
|
communicate with each other via broadcasts (using mailslots) and
|
|
private RPC.
|
|
|
|
Author:
|
|
|
|
Steven Zeck (stevez) 07/01/90
|
|
|
|
--*/
|
|
|
|
#include "core.hxx"
|
|
extern "C" {
|
|
#include "nsicom.h"
|
|
#include "loctoloc.h"
|
|
}
|
|
|
|
#include "mailslot.hxx"
|
|
|
|
extern "C" {
|
|
#include <string.h>
|
|
#include "locquery.h"
|
|
}
|
|
|
|
#include "locclass.hxx"
|
|
extern NATIVE_CLASS_LOCATOR * Locator;
|
|
|
|
/*
|
|
|
|
These prototypes are handcrafted from MIDL derived ones
|
|
Gross, but then this is the locator.
|
|
*/
|
|
|
|
extern "C" {
|
|
void CLIENT_I_nsi_lookup_begin(
|
|
handle_t hrpcPrimaryLocatorHndl,
|
|
UNSIGNED32 entry_name_syntax,
|
|
STRING_T entry_name,
|
|
NSI_SYNTAX_ID_T *interfaceid,
|
|
NSI_SYNTAX_ID_T *xfersyntax,
|
|
NSI_UUID_P_T obj_uuid,
|
|
UNSIGNED32 binding_max_count,
|
|
UNSIGNED32 ignore,
|
|
NSI_NS_HANDLE_T *import_context,
|
|
UNSIGNED16 *status);
|
|
void CLIENT_I_nsi_lookup_done(
|
|
handle_t hrpcPrimaryLocatorHndl,
|
|
NSI_NS_HANDLE_T *import_context,
|
|
UNSIGNED16 *status);
|
|
void CLIENT_I_nsi_lookup_next(
|
|
handle_t hrpcPrimaryLocatorHndl,
|
|
NSI_NS_HANDLE_T import_context,
|
|
NSI_BINDING_VECTOR_P_T *binding_vector,
|
|
UNSIGNED16 *status);
|
|
|
|
void CLIENT_I_nsi_entry_object_inq_begin(
|
|
handle_t hrpcPrimaryLocatorHndl,
|
|
UNSIGNED32 EntryNameSyntax,
|
|
STRING_T EntryName,
|
|
NSI_NS_HANDLE_T *InqContext,
|
|
UNSIGNED16 *status);
|
|
|
|
void CLIENT_I_nsi_entry_object_inq_done(
|
|
NSI_NS_HANDLE_T *InqContext,
|
|
UNSIGNED16 *status);
|
|
|
|
void CLIENT_I_nsi_entry_object_inq_next(
|
|
handle_t hrpcPrimaryLoctorHndl,
|
|
NSI_NS_HANDLE_T InqContext,
|
|
NSI_UUID_VECTOR_P_T *uuid_vec,
|
|
UNSIGNED16 *status);
|
|
}
|
|
|
|
READ_MAIL_SLOT *hMailSlot;
|
|
const long idlePenlity = 5000L; // time to idle if you are too pushy
|
|
|
|
typedef struct { // format of the PS back on the net
|
|
UICHAR Domain[DOMAIN_MAX]; // buffer for machine name
|
|
char Buffer[1000];
|
|
} NetReply;
|
|
|
|
|
|
#define LOCLOC_PROTSEQ "ncacn_np"
|
|
#define LOCLOC_PIPEADDR "\\pipe\\locator"
|
|
|
|
|
|
|
|
STATUS
|
|
NetLookUpNext(
|
|
REPLY_SERVER_ITEM *pRP,
|
|
char * Buffer,
|
|
long UNALIGNED * cbBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return additional Protocol stacks found with LockUp.
|
|
|
|
Arguments:
|
|
|
|
pRP - place to continue search with
|
|
|
|
Buffer - buffer to place protocol stack results
|
|
|
|
cbBuffer - buffer size on input
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
DLIST(3, "LookupNext: " << hex(long(pRP)) << nl);
|
|
|
|
ENTRY_BASE_ITEM * BaseItem;
|
|
long cbUsed;
|
|
STATUS Status = NSI_S_NO_MORE_BINDINGS;
|
|
|
|
if (!pRP)
|
|
return(Status);
|
|
|
|
CLAIM_MUTEX Update(pESaccess);
|
|
|
|
*cbBuffer -= sizeof(long); // Reserve space for terminating type.
|
|
|
|
// first go through and compute the number of PS that can fit in the buffer
|
|
|
|
while(BaseItem = pRP->NextBaseItem()) {
|
|
|
|
DLIST(4, *BaseItem);
|
|
|
|
cbUsed = BaseItem->Marshall(Buffer, cbBuffer);
|
|
|
|
if (cbUsed == 0)
|
|
break;
|
|
|
|
Buffer += cbUsed;
|
|
Status = NSI_S_OK;
|
|
}
|
|
|
|
*(long UNALIGNED *)Buffer = 0; // 0 terminate marshalled buffer
|
|
|
|
ASSERT(AssertHeap());
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
void
|
|
QueryProcess(
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
{
|
|
STATUS Status = 0;
|
|
int MailStatus;
|
|
int cbReturnName;
|
|
long cbPSback;
|
|
NetReply NRback;
|
|
QueryPacket NetQuery;
|
|
REPLY_SERVER_ITEM *LookupHandle;
|
|
short LookupStatus;
|
|
|
|
DLIST(2, "starting query server...\n");
|
|
|
|
// create both an server (s) and client (c) side mailslotes
|
|
|
|
READ_MAIL_SLOT hMailslotAdvertize(PMAILNAME_S, sizeof(NetQuery),
|
|
&MailStatus);
|
|
|
|
if (MailStatus)
|
|
AbortServer("Error in new mailslot", MailStatus);
|
|
|
|
hMailSlot = new READ_MAIL_SLOT(PMAILNAME_C, sizeof(NetReply),
|
|
&MailStatus);
|
|
|
|
if (!hMailSlot)
|
|
AbortServer("Out of memory");
|
|
|
|
if (MailStatus)
|
|
AbortServer("Error in new mailslot", MailStatus);
|
|
|
|
|
|
NRback.Domain[0] = NIL;
|
|
CatUZ(NRback.Domain, DomainName);
|
|
|
|
while (1) {
|
|
|
|
ASSERT(AssertHeap());
|
|
|
|
MailStatus = hMailslotAdvertize.Read((PB) &NetQuery, cbReturnName);
|
|
|
|
if (MailStatus)
|
|
AbortServer("Mailslot read error", MailStatus);
|
|
|
|
// ignore messages to self, sending a request on a mailslote
|
|
// by a lookUp request will be delivered to the local slot too.
|
|
|
|
if (!CmpUZ(NetQuery.WkstaName, SelfName))
|
|
continue;
|
|
|
|
//Since the machine broadcasted, it is probably a master locator
|
|
//If we are not a master locator, insert the broadcaster in
|
|
//our cache!
|
|
|
|
if (Locator->InqIfIamMasterLocator() != TRUE)
|
|
{
|
|
Locator->CacheThisServer(NetQuery.WkstaName);
|
|
}
|
|
|
|
// form a query and call the normal lookup to get a reply
|
|
|
|
perf.cNetRequests++;
|
|
|
|
{
|
|
ENTRY_KEY Entry(NetQuery.EntryName, TRUE, &Status);
|
|
|
|
if (Status)
|
|
continue;
|
|
|
|
QUERY_SERVER * pQuery =
|
|
new QUERY_SERVER (&Entry, &NetQuery.Interface, &NilSyntaxID,
|
|
&NetQuery.Object, NS_LOCAL_INTERFACE |
|
|
(Entry.IsNil())? 0: NS_FULLPATH_INTERFACE,
|
|
&Status);
|
|
|
|
if (Status)
|
|
continue;
|
|
|
|
DLIST(3, NetQuery.WkstaName << " requested " << NetQuery.Interface << nl);
|
|
|
|
cbPSback = sizeof(NRback.Buffer);
|
|
|
|
LookupStatus = NetLookUp(&LookupHandle, pQuery);
|
|
|
|
if (LookupStatus != NSI_S_OK)
|
|
delete pQuery;
|
|
|
|
// form the name of the return mail slot, from the request
|
|
|
|
UICHAR ReturnName[sizeof(MAILNAME(c)) + sizeof(NetQuery.WkstaName)];
|
|
|
|
ReturnName[0] = NIL;
|
|
CatUZ(CatUZ(ReturnName, NetQuery.WkstaName), PMAILNAME_C);
|
|
|
|
{
|
|
WRITE_MAIL_SLOT MSReply(ReturnName, NIL, &Status);
|
|
|
|
// for all the return PS, write then back to the net
|
|
|
|
while (LookupStatus == 0 && Status == 0) {
|
|
|
|
cbPSback = sizeof(NRback.Buffer);
|
|
|
|
LookupStatus = NetLookUpNext(LookupHandle,
|
|
NRback.Buffer, &cbPSback);
|
|
|
|
if (! LookupStatus)
|
|
MailStatus = MSReply.Write((char *) &NRback,
|
|
(WORD) sizeof(NRback.Buffer) - cbPSback +
|
|
sizeof(NRback.Domain));
|
|
|
|
if (MailStatus)
|
|
break;
|
|
}
|
|
|
|
if (LookupHandle)
|
|
NetLookUpClose(LookupHandle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
ENTRY_BASE_ITEM::Marshall(
|
|
OUT PB Buffer,
|
|
IN long UNALIGNED *cbBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Base class method, never should be called.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!"ENTRY_BASE_ITEM::Marshall");
|
|
if ((Buffer) || (*cbBuffer))
|
|
;
|
|
return(0);
|
|
}
|
|
|
|
|
|
PB
|
|
UnMarshallServerEntry(
|
|
IN PUZ Domain,
|
|
IN PB Buffer,
|
|
OUT STATUS *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unmarshall a single server entry object.
|
|
|
|
Arguments:
|
|
|
|
Domain - Domain of were the entry came from
|
|
|
|
Buffer - Input buffer to unmarshall from
|
|
|
|
Returns:
|
|
|
|
Pointer to the next record
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// AlignedBuffer, being on the stack, should be word-aligned.
|
|
// Copying the ENTRY_SERVER_ITEM from the unaligned buffer
|
|
// to AlignedBuffer should align all its members properly, so that Steve's
|
|
// trick of casting a buffer to an object will work.
|
|
//
|
|
char AlignedBuffer[sizeof(ENTRY_SERVER_ITEM)];
|
|
|
|
memcpy(AlignedBuffer, Buffer, sizeof(ENTRY_SERVER_ITEM));
|
|
Buffer += sizeof(ENTRY_SERVER_ITEM);
|
|
|
|
ENTRY_SERVER_ITEM * ServerItem = (ENTRY_SERVER_ITEM *) AlignedBuffer;
|
|
|
|
//
|
|
// Now unmarshal the ENTRY_KEY.
|
|
//
|
|
ENTRY_KEY * Entry = 0;
|
|
Buffer = KeyEntryUnMarshall((ENTRY_KEY **)&Entry, Domain, Buffer, Status);
|
|
|
|
if (*Status)
|
|
return(NIL);
|
|
|
|
//
|
|
// Gotta create a UUID_ARRAY that is properly aligned. Use marshalled
|
|
// size to create a new UUID_ARRAY, and copy the marshalled uuids into
|
|
// its buffer.
|
|
//
|
|
// We used to say
|
|
//
|
|
// ObjectDA = *((UUID_ARRAY __unaligned *) Buffer);
|
|
//
|
|
// but the compiler seems to ignore the __unaligned directive in that case.
|
|
//
|
|
LONG UNALIGNED * UuidCountPtr = (LONG UNALIGNED *) Buffer;
|
|
Buffer += sizeof(UUID_ARRAY);
|
|
|
|
UUID_ARRAY ObjectDA(*UuidCountPtr);
|
|
|
|
if (ObjectDA.cCur())
|
|
{
|
|
if (!ObjectDA.pCur())
|
|
{
|
|
*Status = NSI_S_OUT_OF_MEMORY;
|
|
|
|
Entry->Free();
|
|
delete Entry;
|
|
return(NIL);
|
|
}
|
|
|
|
memcpy(ObjectDA.pCur(), Buffer, ObjectDA.Size());
|
|
Buffer += ObjectDA.Size();
|
|
}
|
|
|
|
PUZ Binding = (UICHAR *)Buffer;
|
|
|
|
Buffer += ServerItem->TheStringBinding().Size();
|
|
|
|
ServerItem = new ENTRY_SERVER_ITEM(CacheItemType,
|
|
&ServerItem->TheInterface(),
|
|
&ServerItem->TheTransferSyntax(),
|
|
Binding, Status);
|
|
|
|
if (!ServerItem)
|
|
*Status = NSI_S_OUT_OF_MEMORY;
|
|
|
|
if (! *Status)
|
|
*Status = InsertServerEntry(Entry, ServerItem, &ObjectDA);
|
|
|
|
ObjectDA.Free();
|
|
Entry->Free();
|
|
delete Entry;
|
|
|
|
return(Buffer);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
UpdateLocalCache (
|
|
IN UNSIGNED32 EntryNameSyntax,
|
|
IN STRING_T EntryName,
|
|
IN NS_SYNTAX_ID * Interface,
|
|
IN NS_SYNTAX_ID * XferSyntax,
|
|
IN STRING_T StringBinding,
|
|
IN NSI_UUID_VECTOR_P_T ObjectVector,
|
|
IN UNSIGNED16 *Status
|
|
)
|
|
/*
|
|
|
|
|
|
Called by GetUpdateFromMasterLocator, which gets the entries and
|
|
wants to update the local cache
|
|
|
|
*/
|
|
{
|
|
|
|
UUID_ARRAY ObjectDA;
|
|
|
|
if (ObjectVector != NULL)
|
|
{
|
|
ObjectDA = UUID_ARRAY(ObjectVector->count);
|
|
|
|
NS_UUID ** pGID = (NS_UUID **) ObjectVector->uuid;
|
|
for (UUID_ARRAY_ITER ODi(ObjectDA); ODi; ++ODi, ++pGID)
|
|
*ODi = **pGID;
|
|
}
|
|
|
|
if (EntryName == NIL)
|
|
{
|
|
DLIST(3, "[Error]:UpdLocalCache got bogus EntryName\n");
|
|
*Status = NSI_S_INCOMPLETE_NAME;
|
|
}
|
|
|
|
if (EntryNameSyntax != RPC_C_NS_SYNTAX_DCE)
|
|
{
|
|
DLIST(3, "[Error]:UpdLocalCache got bogus EntryNameSyntax\n");
|
|
*Status = NSI_S_UNSUPPORTED_NAME_SYNTAX;
|
|
}
|
|
|
|
ENTRY_KEY EntryObj(EntryName, TRUE, Status);
|
|
if (*Status)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ENTRY_SERVER_ITEM *
|
|
ServerItem = new ENTRY_SERVER_ITEM (
|
|
CacheItemType,
|
|
Interface,
|
|
XferSyntax,
|
|
(PUZ)StringBinding,
|
|
Status
|
|
);
|
|
|
|
if (ServerItem == NULL)
|
|
{
|
|
*Status = NSI_S_OUT_OF_MEMORY;
|
|
return;
|
|
}
|
|
|
|
if (*Status)
|
|
{
|
|
delete ServerItem;
|
|
return;
|
|
}
|
|
|
|
*Status = InsertServerEntry(&EntryObj, ServerItem, &ObjectDA);
|
|
|
|
ObjectDA.Free();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
ENTRY_SERVER_ITEM::Marshall(
|
|
PB Buffer,
|
|
long UNALIGNED *cbBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function linearizes a list of protocol stacks into a buffer
|
|
to be returned to the client. The client function NormalizePTR is
|
|
the corresponding unMarshall function to this data structure.
|
|
|
|
Arguments:
|
|
|
|
Buffer - pointer to memory to marshall this stuff
|
|
|
|
cbBuffer - pointer to the size of buffer.
|
|
|
|
Returns:
|
|
|
|
The number of bytes consummed.
|
|
|
|
--*/
|
|
{
|
|
int cbNeeded;
|
|
|
|
// first determine the size of buffer needed for this object.
|
|
|
|
cbNeeded = sizeof(long) +
|
|
sizeof(ENTRY_SERVER_ITEM) +
|
|
TheEntry().MarshallSize() +
|
|
TheObjectDA().MarshallSize() +
|
|
StringBinding.Size();
|
|
|
|
if (cbNeeded > *cbBuffer)
|
|
return(FALSE);
|
|
|
|
*cbBuffer -= cbNeeded;
|
|
|
|
// First, place a tag for the type of entry.
|
|
|
|
*(long UNALIGNED *)Buffer = ServerEntryType;
|
|
Buffer += sizeof(long);
|
|
|
|
// Then marshall the object and the referenced parts.
|
|
|
|
Buffer = Copy(Buffer, this, sizeof(ENTRY_SERVER_ITEM));
|
|
Buffer = TheEntry().Marshall(Buffer);
|
|
Buffer = TheObjectDA().Marshall(Buffer);
|
|
|
|
if (StringBinding.cCur())
|
|
Buffer = StringBinding.CopyBuff(Buffer);
|
|
|
|
ASSERT(AssertHeap());
|
|
|
|
return (cbNeeded);
|
|
}
|
|
|
|
|
|
PB
|
|
UnMarshallGroupEntry(
|
|
IN UICHAR *Domain,
|
|
IN PB Buffer,
|
|
OUT STATUS *Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unmarshall a single Group entry object.
|
|
|
|
Arguments:
|
|
|
|
Domain - Domain of that the entry came from
|
|
|
|
Buffer - Input buffer to unmarshall from
|
|
|
|
Returns:
|
|
|
|
Pointer to the next record
|
|
|
|
--*/
|
|
{
|
|
// Unmarshall the buffer into their componet objects
|
|
// and then add it to the entry data base.
|
|
|
|
ENTRY_KEY *Entry;
|
|
ENTRY_GROUP_ITEM *GroupItem;
|
|
UICHAR *Member;
|
|
|
|
GroupItem = (ENTRY_GROUP_ITEM *) Buffer;
|
|
Buffer += sizeof(ENTRY_GROUP_ITEM);
|
|
|
|
Entry = (ENTRY_KEY *) Buffer;
|
|
Buffer = KeyEntryUnMarshall(&Entry, Domain, Buffer, Status);
|
|
|
|
if (*Status)
|
|
return(0);
|
|
|
|
Member = (UICHAR *)Buffer;
|
|
Buffer += GroupItem->TheMember().Size();
|
|
|
|
GroupItem = new ENTRY_GROUP_ITEM(CacheItemType, Member, Status);
|
|
|
|
if (!GroupItem)
|
|
*Status = NSI_S_OUT_OF_MEMORY;
|
|
|
|
if (! *Status)
|
|
*Status = InsertGroupEntry(Entry, GroupItem);
|
|
|
|
Entry->Free();
|
|
delete Entry;
|
|
|
|
return(Buffer);
|
|
}
|
|
|
|
|
|
int
|
|
ENTRY_GROUP_ITEM::Marshall(
|
|
OUT PB Buffer,
|
|
IN long UNALIGNED *cbBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function linearizes a list of protocol stacks into a buffer
|
|
to be returned to the client. The client function NormalizePTR is
|
|
the corresponding unMarshall function to this data structure.
|
|
|
|
Arguments:
|
|
|
|
Buffer - pointer to memory to marshall this stuff
|
|
|
|
cbBuffer - pointer to the size of buffer.
|
|
|
|
Returns:
|
|
|
|
The number of bytes consummed.
|
|
|
|
--*/
|
|
{
|
|
int cbNeeded;
|
|
|
|
// first determine the size of buffer needed for this object.
|
|
|
|
cbNeeded = sizeof(long) +
|
|
sizeof(ENTRY_GROUP_ITEM) +
|
|
EntryNode->TheEntry().MarshallSize() +
|
|
Member.Size();
|
|
|
|
if (cbNeeded > *cbBuffer)
|
|
return(FALSE);
|
|
|
|
*cbBuffer -= cbNeeded;
|
|
|
|
// First, place a tag for the type of entry.
|
|
|
|
*(long UNALIGNED *)Buffer = GroupEntryType;
|
|
Buffer += sizeof(long);
|
|
|
|
// Then marshall the object and the referenced parts.
|
|
|
|
Buffer = Copy(Buffer, this, sizeof(ENTRY_GROUP_ITEM));
|
|
Buffer = EntryNode->TheEntry().Marshall(Buffer);
|
|
Buffer = Member.CopyBuff(Buffer);
|
|
|
|
ASSERT(AssertHeap());
|
|
|
|
return (cbNeeded);
|
|
}
|
|
|
|
|
|
|
|
STATUS
|
|
QUERY::QueryNet(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Base class method, never should be called.
|
|
|
|
--*/
|
|
{
|
|
ASSERT(!"QUERY::QueryNet");
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
STATUS
|
|
QUERY_SERVER::QueryNet(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look on the net for more servers
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
QueryPacket NetRequest;
|
|
|
|
DLIST(3, "QueryNet for: " << Entry << nl <<
|
|
" " << Interface << nl);
|
|
|
|
// format a request which contains my own name and the GID I'm
|
|
// looking for
|
|
|
|
memset(&NetRequest, 0, sizeof(NetRequest));
|
|
NetRequest.Interface = Interface;
|
|
NetRequest.Object = Object;
|
|
|
|
return(BroadCast(NetRequest, Entry));
|
|
}
|
|
|
|
|
|
STATUS
|
|
QUERY::BroadCast(
|
|
IN QueryPacket& NetRequest,
|
|
IN ENTRY_KEY& Entry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This function is called by lookUp when the local list Protocol Stacks
|
|
needs updating from the net. It broadcasts on the current domain
|
|
on a mailslot listened to by other locators (function Advertise).
|
|
|
|
Arguments:
|
|
|
|
NetRequest - formated buffer for a net query
|
|
|
|
Returns:
|
|
|
|
TRUE - if there was new information from over the net.
|
|
|
|
--*/
|
|
{
|
|
STATUS Status;
|
|
PB Buffer;
|
|
int MailStatus;
|
|
BOOL fReturn = FALSE;
|
|
static long timeLast; // last time the GID was queried for
|
|
static long timeTotal; // total time querying the net
|
|
long timeStart; // time started the query
|
|
ULONG waitCur = waitOnRead; // current wait time for replys
|
|
PUZ ForeignDomain, Domain;
|
|
long Type;
|
|
UICHAR DomainBuffer[DOMAIN_MAX];
|
|
|
|
int cbRead;
|
|
NetReply NRquery;
|
|
|
|
if (!hMailSlot) // net not started, just return
|
|
return(NSI_S_ENTRY_NOT_FOUND);
|
|
|
|
NetRequest.WkstaName[0] = NIL;
|
|
CatUZ(NetRequest.WkstaName, SelfName);
|
|
Domain = Entry.MakeLocalName(NetRequest.EntryName, DomainBuffer,
|
|
HOME_DOMAIN);
|
|
|
|
CLAIM_MUTEX Update(pESnet);
|
|
|
|
timeStart = CurrentTimeMS();
|
|
timeLast = CurrentTime();
|
|
|
|
WRITE_MAIL_SLOT MSquery(PMAILNAME_S, Domain, &Status);
|
|
if (Status)
|
|
return(NSI_S_ENTRY_NOT_FOUND);
|
|
|
|
MailStatus = MSquery.Write((PB) &NetRequest, sizeof(NetRequest));
|
|
|
|
if (MailStatus)
|
|
return(NSI_S_ENTRY_NOT_FOUND);
|
|
|
|
if (OtherDomain && NetRequest.EntryName[0] == NIL) {
|
|
|
|
WRITE_MAIL_SLOT AltDomain(PMAILNAME_S, OtherDomain, &Status);
|
|
|
|
if (!Status)
|
|
MailStatus = AltDomain.Write((PB) &NetRequest,
|
|
sizeof(NetRequest));
|
|
}
|
|
|
|
// now loop waiting for responses from other RPC servers
|
|
|
|
cbRead = sizeof(NRquery);
|
|
|
|
while (!hMailSlot->Read((char *) &NRquery, cbRead, waitCur)) {
|
|
|
|
if (cbRead == 0)
|
|
{
|
|
//wierd - got a 0 byte read
|
|
cbRead = sizeof(NRquery);
|
|
continue;
|
|
}
|
|
|
|
Buffer = NRquery.Buffer;
|
|
ForeignDomain = (wcsicmp(DomainName, NRquery.Domain) == 0)?
|
|
NIL: NRquery.Domain;
|
|
|
|
while (*(long UNALIGNED *) Buffer && !Status) {
|
|
|
|
Type = *(long UNALIGNED *) Buffer;
|
|
Buffer += sizeof(long);
|
|
|
|
switch(Type) {
|
|
|
|
case ServerEntryType:
|
|
Buffer = UnMarshallServerEntry(ForeignDomain, Buffer, &Status);
|
|
break;
|
|
|
|
case GroupEntryType:
|
|
Buffer = UnMarshallGroupEntry(ForeignDomain, Buffer, &Status);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(!"Unknown buffer type for reply");
|
|
break;
|
|
}
|
|
}
|
|
|
|
cbRead = sizeof(NRquery);
|
|
fReturn = TRUE;
|
|
|
|
// half the wait period everytime you get a response from the net
|
|
|
|
waitCur >>= 1;
|
|
}
|
|
|
|
timeTotal += CurrentTimeMS() - timeStart;
|
|
|
|
perf.averageNetTime = (int) (timeTotal / ++perf.cNetQuery);
|
|
|
|
if (Status)
|
|
return(Status);
|
|
|
|
return ((fReturn)? NSI_S_OK: NSI_S_ENTRY_NOT_FOUND);
|
|
}
|
|
|
|
|
|
STATUS
|
|
QUERY_GROUP::QueryNet(
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look on the net for more servers
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
QueryPacket NetRequest;
|
|
|
|
DLIST(3, "QueryNet for Group: " << Entry << nl);
|
|
|
|
// format a request which contains my own name and the GID I'm
|
|
// looking for
|
|
|
|
memset(&NetRequest, 0, sizeof(NetRequest));
|
|
|
|
return(BroadCast(NetRequest, Entry));
|
|
}
|
|
|
|
|
|
/*
|
|
QUERY_SERVERs implementation of point-point updates!
|
|
|
|
*/
|
|
|
|
STATUS
|
|
QUERY::GetUpdatesFromMasterLocator(
|
|
)
|
|
{
|
|
|
|
ASSERT(!"Nothing should ever call this \n");
|
|
return(0);
|
|
|
|
}
|
|
|
|
STATUS
|
|
QUERY_SERVER::GetUpdatesFromMasterLocator(
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
Binds to the MasterLocator, gets bindinghandles for the entry name
|
|
specified in the QUERY object. If master doesnt have anything in the
|
|
query, [s]he will broadcast- so the QUERY->Search routine should
|
|
*NOT* broadcast if we got no replies from the master!
|
|
The only reason for QUERY->Search to Broadcast is if we couldnt
|
|
bind to a MASTER LOCATOR!
|
|
*/
|
|
|
|
{
|
|
|
|
DLIST(3, "Here is where we get the real stuff from master" << nl);
|
|
|
|
handle_t PrimaryLocHandle = NULL;
|
|
NSI_NS_HANDLE_T LookupHandle, ObjectHandle;
|
|
NSI_BINDING_VECTOR_P_T BindingVector = 0;
|
|
int Status = 0;
|
|
STATUS LocErr = 0, LocEr2=0, Error=0;
|
|
unsigned char * StringBinding = 0;
|
|
BOOL TriedOnceAlready = FALSE;
|
|
BOOL UpdateNeeded = FALSE;
|
|
NSI_UUID_VECTOR_P_T UuidVector = 0;
|
|
STRING_T EntryNameString = 0;
|
|
|
|
|
|
//
|
|
//special case NULL lookups !
|
|
//
|
|
if (Entry.TheEntryName().cCur() != 0)
|
|
{
|
|
if ( (EntryNameString = (STRING_T)Entry.CopyName()) == 0)
|
|
return(NSI_S_OUT_OF_MEMORY);
|
|
}
|
|
|
|
for(; ;)
|
|
{
|
|
PrimaryLocHandle = Locator->GetBindingToMasterLocator(&Status);
|
|
|
|
if ( (Status) || (PrimaryLocHandle == 0) )
|
|
{
|
|
// BUGBUG I don't understand why this assert is too restrictive
|
|
// in a Cairo domain.
|
|
//
|
|
// ASSERT(Status == RPC_S_SERVER_UNAVAILABLE);
|
|
return(NSI_S_NO_MASTER_LOCATOR);
|
|
}
|
|
|
|
RpcTryExcept
|
|
{
|
|
CLIENT_I_nsi_lookup_begin(
|
|
PrimaryLocHandle,
|
|
RPC_C_NS_SYNTAX_DCE,
|
|
EntryNameString,
|
|
(NSI_SYNTAX_ID_T *)&Interface,
|
|
(NSI_SYNTAX_ID_T *)&TransferSyntax,
|
|
(NSI_UUID_P_T) &Object,
|
|
MAX_OBJECT_SIZE,
|
|
0,
|
|
&LookupHandle,
|
|
&LocErr
|
|
);
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
LocErr = NSI_S_NO_MASTER_LOCATOR;
|
|
}
|
|
RpcEndExcept
|
|
|
|
//Try twice
|
|
//If we had bound to master before, GetBi..ToMaster returns the same
|
|
//binding without pinging. So if masterloc has gone down since then
|
|
//we may get a RPC_S_UNAVAILABLE .. Destroy the binding and try again
|
|
|
|
if (LocErr != NSI_S_OK)
|
|
{
|
|
if (TriedOnceAlready == FALSE)
|
|
{
|
|
LocErr = NSI_S_OK;
|
|
Locator->DestroyBindingToMasterLocator();
|
|
TriedOnceAlready = TRUE;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
RpcTryExcept
|
|
{
|
|
CLIENT_I_nsi_lookup_next(
|
|
PrimaryLocHandle,
|
|
LookupHandle,
|
|
(NSI_BINDING_VECTOR_P_T *)&BindingVector,
|
|
&LocErr
|
|
);
|
|
}
|
|
RpcExcept(1)
|
|
{
|
|
LocErr = NSI_S_NO_MORE_BINDINGS;
|
|
}
|
|
RpcEndExcept
|
|
|
|
if ( (LocErr == NSI_S_NO_MORE_BINDINGS)
|
|
|| (LocErr == NSI_S_ENTRY_NOT_FOUND))
|
|
break;
|
|
|
|
|
|
for (unsigned int i = 0; i < BindingVector->count; i++)
|
|
{
|
|
|
|
DLIST(3, " upding local w/\n" <<
|
|
BindingVector->binding[i].string << nl);
|
|
|
|
DLIST(3, " upding local w/\n" <<
|
|
BindingVector->binding[i].entry_name << nl);
|
|
|
|
CLIENT_I_nsi_entry_object_inq_begin(
|
|
PrimaryLocHandle,
|
|
BindingVector->binding[i].entry_name_syntax,
|
|
BindingVector->binding[i].entry_name,
|
|
&ObjectHandle,
|
|
&Error
|
|
);
|
|
|
|
if (Error == NSI_S_OK)
|
|
{
|
|
CLIENT_I_nsi_entry_object_inq_next(
|
|
PrimaryLocHandle,
|
|
ObjectHandle,
|
|
&UuidVector,
|
|
&Error
|
|
);
|
|
}
|
|
|
|
if (Error != NSI_S_OK)
|
|
UuidVector = 0;
|
|
|
|
UpdateLocalCache(
|
|
BindingVector->binding[i].entry_name_syntax,
|
|
BindingVector->binding[i].entry_name,
|
|
&Interface,
|
|
&TransferSyntax,
|
|
BindingVector->binding[i].string,
|
|
UuidVector,
|
|
&LocErr
|
|
);
|
|
|
|
CLIENT_I_nsi_entry_object_inq_done(
|
|
&ObjectHandle,
|
|
&Error
|
|
);
|
|
|
|
for (unsigned int j = 0; UuidVector && j < UuidVector->count; j++)
|
|
MIDL_user_free((void *) UuidVector->uuid[j]);
|
|
|
|
if (UuidVector != 0)
|
|
MIDL_user_free((void *) UuidVector);
|
|
|
|
UuidVector = 0;
|
|
|
|
MIDL_user_free((void *)BindingVector->binding[i].entry_name);
|
|
MIDL_user_free((void *)BindingVector->binding[i].string);
|
|
} //for each binding vector/entryname returned.
|
|
|
|
MIDL_user_free((void *)BindingVector);
|
|
BindingVector = 0;
|
|
|
|
} //end while
|
|
|
|
|
|
CLIENT_I_nsi_lookup_done(
|
|
PrimaryLocHandle,
|
|
&LookupHandle,
|
|
&LocEr2
|
|
);
|
|
|
|
break;
|
|
|
|
} //end of for(;;)
|
|
|
|
if (EntryNameString != 0)
|
|
delete EntryNameString;
|
|
|
|
if (PrimaryLocHandle != 0)
|
|
RpcBindingFree(&PrimaryLocHandle);
|
|
|
|
return(LocErr);
|
|
|
|
}
|
|
|
|
/*
|
|
QUERY_GROUPs implementation of point-point updates!
|
|
|
|
*/
|
|
STATUS
|
|
QUERY_GROUP::GetUpdatesFromMasterLocator(
|
|
)
|
|
{
|
|
|
|
DLIST(3, "Here is where we get the real stuff from master" << nl);
|
|
return(0);
|
|
}
|
|
|
|
char *
|
|
QUERY::DetectMasterLocator(
|
|
)
|
|
{
|
|
|
|
return("\\\\barats486");
|
|
}
|
|
|
|
|
|
|
|
|
|
STATUS
|
|
NetLookUp(
|
|
OUT REPLY_SERVER_ITEM **pRPOut,
|
|
IN QUERY_SERVER *aQuery
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API tries to find a Protocol stack that matchs the input
|
|
search criteria. It will return as many PS that fit in the buffer
|
|
supplied. If there are too many, then a context handle is allocated
|
|
which contains a Linked List of PS to return, with LookUpNext.
|
|
|
|
Arguments:
|
|
|
|
pRPOut - context handle for Next.
|
|
|
|
aQuery - server entry that I'm looking for
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
DLIST(3, "LocLookup\n");
|
|
|
|
STATUS Status;
|
|
|
|
*pRPOut = NIL;
|
|
|
|
CLAIM_MUTEX Update(pESaccess);
|
|
perf.cLookUp++;
|
|
|
|
// Search the entire list, assembling a reply into a Marshall list.
|
|
|
|
if ((Status = aQuery->Search()) == NSI_S_OK) {
|
|
|
|
// more PS to return then there is memory, allocate a search handle
|
|
|
|
REPLY_SERVER_ITEM *pRPLook = new REPLY_SERVER_ITEM(aQuery);
|
|
|
|
if (!pRPLook)
|
|
return(NSI_S_OUT_OF_MEMORY);
|
|
|
|
DLIST(4, "Allocating search handle " << hex(long(pRPLook)) << nl);
|
|
|
|
*pRPOut = pRPLook;
|
|
}
|
|
|
|
ASSERT(AssertHeap());
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
STATUS
|
|
NetLookUpClose(
|
|
IN REPLY_SERVER_ITEM *pRP
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free the context handles resources allocated in LookUp
|
|
|
|
Arguments:
|
|
|
|
pRP - handle to close
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
DLIST(3, "LookupClose: " << hex(long(pRP)) << nl);
|
|
|
|
CLAIM_MUTEX Update(pESaccess);
|
|
|
|
if (pRP)
|
|
delete(pRP);
|
|
|
|
ASSERT(AssertHeap());
|
|
|
|
return(NSI_S_OK);
|
|
}
|
|
|
|
|
|
ostream& operator << ( // output a formated STATICTS structure
|
|
|
|
OUT ostream& pSB, // stream buffer to write to
|
|
IN STATICTS& pSTAT // and the STATICS
|
|
|
|
)/*-----------------------------------------------------------------------*/
|
|
{
|
|
#define outField(NAME) pSB << #NAME": " << pSTAT.NAME << nl
|
|
|
|
pSB << "Performance statics for: " << SelfName << nl;
|
|
|
|
outField(cExports);
|
|
outField(cCached);
|
|
outField(cLookUp);
|
|
outField(cNetQuery);
|
|
outField(cNetRequests);
|
|
outField(averageNetTime);
|
|
outField(cDiscard);
|
|
outField(cTimeOut);
|
|
return (pSB << nl);
|
|
}
|