windows-nt/Source/XPSP1/NT/com/rpc/locator/client/nsiclnt.cxx
2020-09-26 16:20:57 +08:00

803 lines
18 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 1992 - 1999
Module Name:
nsiclnt.cxx
Abstract:
This is the client side NSI service support layer. These are wrappers
which call the name service provider.
Author:
Steven Zeck (stevez) 03/04/92
--*/
#include <nsi.h>
#include <string.h>
#include <time.h>
// This structure is used in binding handle select processing.
typedef struct
{
unsigned long Count;
int IndexMatch[1];
} MATCH_VECTOR;
RPC_STATUS RPC_ENTRY
I_NsBindingFoundBogus(RPC_BINDING_HANDLE *BindingHandle, DWORD BindId);
RPC_STATUS RPC_ENTRY
I_NsClientBindSearch(RPC_BINDING_HANDLE *NsiClntBinding, DWORD *BindId);
void RPC_ENTRY
I_NsClientBindDone(RPC_BINDING_HANDLE *NsiClntBinding, DWORD BindId);
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupBeginW(
IN unsigned long EntryNameSyntax,
IN unsigned short __RPC_FAR * EntryName,
IN RPC_IF_HANDLE RpcIfHandle,
IN UUID __RPC_FAR * Object OPTIONAL,
IN unsigned long BindingMaxCount,
OUT RPC_NS_HANDLE *LookupContext
)
/*++
Routine Description:
Query the named server for the requested binding handles. This will
request a query from name server to be performed and store the results
to be retrieved with RpcNsBindingLookupNext().
Arguments:
EntryNameSyntax - This value describes the type/format of the EntryName.
EntryName - Name that this export will be stored in. This is just a
token that is passed on the the Name Server.
RpcIfHandle - The interface that is being exported.
Object - the object UUID that you are looking for (or in combination
with RpcIfHandle).
BindingMaxCount - The maxium size of the binding vector to be returned
to the RpcNsBindingLookupNext function.
LookupContext - handle to be used to pass to RpcNsBindingImportNext,
This is really allocated by RpcNsLookupBinding
SearchOptions - used by the auto handle binding routines and Micosoft
name server.
Returns:
RPC_S_OK, RPC_S_NO_MORE_BINDINGS
--*/
{
RPC_STATUS status;
UNSIGNED16 NsiStatus;
NSI_INTERFACE_ID_T NilIfOnWire, __RPC_FAR *IfPtr;
RPC_BINDING_HANDLE NsiClntBinding = NULL;
DWORD BindId = 0;
if (RpcIfHandle == NULL)
{
IfPtr = &NilIfOnWire;
memset(IfPtr, 0, sizeof(NSI_INTERFACE_ID_T));
}
else
{
IfPtr = (NSI_INTERFACE_ID_T __RPC_FAR *)
&((PRPC_CLIENT_INTERFACE)RpcIfHandle)->InterfaceId;
}
while ((status = I_NsClientBindSearch(&NsiClntBinding, &BindId)) == RPC_S_OK)
{
// Provide the default entry name if there is none.
if ((! EntryName || *EntryName == 0) && DefaultName)
{
EntryName = &(*DefaultName);
EntryNameSyntax = DefaultSyntax;
}
else if (! EntryNameSyntax)
EntryNameSyntax = DefaultSyntax;
RpcTryExcept
{
nsi_binding_lookup_begin(NsiClntBinding, EntryNameSyntax, EntryName,
IfPtr,
(NSI_UUID_P_T) Object, BindingMaxCount, 0,
LookupContext, &NsiStatus);
}
RpcExcept(1)
{
*LookupContext = 0;
NsiStatus = MapException(RpcExceptionCode());
}
RpcEndExcept
status = NsiMapStatus(NsiStatus);
if (NsiStatus != NSI_S_NAME_SERVICE_UNAVAILABLE)
break;
I_NsBindingFoundBogus(&NsiClntBinding, BindId);
}
I_NsClientBindDone(&NsiClntBinding, BindId);
return(status);
}
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupNext(
IN RPC_NS_HANDLE LookupContext,
OUT RPC_BINDING_VECTOR **BindingVector
)
/*++
Routine Description:
Retrieve the next group of bindings queryed from RpcNsBindingLookupBegin().
Arguments:
LookupContext - handle to allocated by RpcNsBindingLookupBegin()
BindingVector - returns a pointer to a binding vector.
Returns:
RPC_S_OK, RPC_S_NO_MORE_BINDINGS, RPC_S_OUT_OF_MEMORY,
nsi_binding_lookup_next()
--*/
{
RPC_STATUS status;
UNSIGNED16 NsiStatus;
NSI_BINDING_VECTOR_T * NsiBindingVector;
RPC_BINDING_HANDLE Handle;
unsigned int HandleValide, Index;
NsiBindingVector = 0;
*BindingVector = 0;
RpcTryExcept
{
nsi_binding_lookup_next((NSI_NS_HANDLE_T *) LookupContext,
&NsiBindingVector, &NsiStatus);
}
RpcExcept(1)
{
NsiStatus = MapException(RpcExceptionCode());
}
RpcEndExcept
if (NsiStatus)
return(NsiMapStatus(NsiStatus));
// Convert the string bindings to binding handles. This done by
// replacing the StringBinding with RPC_BINDING_HANDLE to a
// RPC_BINDING_VECTOR allocated by the runtime.
*BindingVector = (RPC_BINDING_VECTOR *) I_RpcAllocate((unsigned int) (
sizeof(RPC_BINDING_VECTOR) - sizeof(RPC_BINDING_HANDLE) +
sizeof(RPC_BINDING_HANDLE) * NsiBindingVector->count));
if (! *BindingVector)
return(RPC_S_OUT_OF_MEMORY);
for (Index = 0, HandleValide = 0;
Index < NsiBindingVector->count; Index++)
{
Handle = 0;
if (!UnicodeToRtString(NsiBindingVector->binding[Index].string))
status = RpcBindingFromStringBinding(
(RT_CHAR *)NsiBindingVector->binding[Index].string, &Handle);
if (!status && NsiBindingVector->binding[Index].entry_name)
{
if (!UnicodeToRtString( NsiBindingVector->binding[Index].entry_name))
{
#ifdef NTENV
status = I_RpcNsBindingSetEntryNameW(Handle,
#else
status = I_RpcNsBindingSetEntryName(Handle,
#endif
NsiBindingVector->binding[Index].entry_name_syntax,
(RT_CHAR *)NsiBindingVector->binding[Index].entry_name);
}
}
if (NsiBindingVector->binding[Index].entry_name)
I_RpcFree(NsiBindingVector->binding[Index].entry_name);
I_RpcFree(NsiBindingVector->binding[Index].string);
// only copy the handle to the output if the Binding was OK.
if (! status)
(*BindingVector)->BindingH[HandleValide++] = Handle;
}
(*BindingVector)->Count = HandleValide;
I_RpcFree(NsiBindingVector);
return((HandleValide > 0)? RPC_S_OK: RPC_S_NO_MORE_BINDINGS);
}
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupDone(
OUT RPC_NS_HANDLE *LookupContext
)
/*++
Routine Description:
Close the context opened with RpcNsBindingLookupBegin();
Arguments:
LookupContext - context handle to close
Returns:
nsi_binding_lookup_done()
--*/
{
UNSIGNED16 NsiStatus = NSI_S_OK;
RpcTryExcept
{
nsi_binding_lookup_done((NSI_NS_HANDLE_T *) LookupContext, &NsiStatus);
}
RpcExcept(1)
{
NsiStatus = MapException(RpcExceptionCode());
}
RpcEndExcept
// RpcBindingFree(&NsiClntBinding);
*LookupContext = 0;
return(NsiMapStatus(NsiStatus));
}
RPC_STATUS RPC_ENTRY
RpcNsBindingImportBeginW(
IN unsigned long EntryNameSyntax,
IN unsigned short __RPC_FAR * EntryName,
IN RPC_IF_HANDLE RpcIfHandle,
IN UUID __RPC_FAR * Object OPTIONAL,
OUT RPC_NS_HANDLE *ImportContextOut
)
/*++
Routine Description:
Query the named server for the requested binding handles. This function
is implemented in terms of RpcNsLookupBinding.
Arguments:
EntryNameSyntax - This value describes the type/format of the EntryName.
EntryName - Name that this export will be stored in. This is just a
token that is passed on the the Name Server.
RpcIfHandle - The interface that is being exported.
Object - the object UUID that you are looking for (or in combination
with RpcIfHandle).
ImportContext - handle to be used to pass to RpcNsBindingImportNext,
This is really allocated by RpcNsLookupBinding
SearchOptions - used by the auto handle binding routines and Micosoft
name server.
Returns:
RpcNsBindingLookupBegin(), RPC_S_OUT_OF_MEMORY, RPS_S_OK
--*/
{
RPC_STATUS status;
RPC_NS_HANDLE LookupContext;
PRPC_IMPORT_CONTEXT_P ImportContext;
const int BindingVectorSize = 10;
*ImportContextOut = 0;
status = RpcNsBindingLookupBeginW(EntryNameSyntax, EntryName,
RpcIfHandle, Object, BindingVectorSize, &LookupContext);
if (status)
return(status);
// Allocate an import context which contains a lookup context,
// a StringBinding vector and an index to the current StringBinding
// in the vector.
if (!(ImportContext = (PRPC_IMPORT_CONTEXT_P)
I_RpcAllocate(sizeof(RPC_IMPORT_CONTEXT_P))) )
return(RPC_S_OUT_OF_MEMORY);
ImportContext->LookupContext = LookupContext;
ImportContext->Bindings = 0;
*ImportContextOut = ImportContext;
return(RPC_S_OK);
}
RPC_STATUS RPC_ENTRY
RpcNsBindingImportNext(
IN RPC_NS_HANDLE ImportContextIn,
OUT RPC_BINDING_HANDLE __RPC_FAR * RpcBinding
)
/*++
Routine Description:
Get the next StringBinding in the Import StringBinding vector. If
the vector is empty, call RpcNsBindingLookupBegin() to get a new
vector.
Arguments:
ImportContext - handle to be used get a new string binding vector from
RpcNsBindingLookupNext()
RpcBinding - place to return a binding. This Binding Handle ownership
passes to caller.
Returns:
RPC_S_OK, RpcNsBindingLookupNext()
--*/
{
RPC_STATUS status;
PRPC_IMPORT_CONTEXT_P ImportContext;
ImportContext = (PRPC_IMPORT_CONTEXT_P) ImportContextIn;
if (!ImportContext)
return(RPC_S_NO_CONTEXT_AVAILABLE);
if (ImportContext->Bindings)
{
status = RpcNsBindingSelect(ImportContext->Bindings, RpcBinding);
if (status == RPC_S_OK)
return(RPC_S_OK);
if (status != RPC_S_NO_MORE_BINDINGS)
return(status);
}
// The vector was empty or there were no more entris. Get another vector.
if (ImportContext->Bindings)
RpcBindingVectorFree(&ImportContext->Bindings);
status = RpcNsBindingLookupNext(ImportContext->LookupContext,
&ImportContext->Bindings);
if (status)
return(status);
return(RpcNsBindingSelect(ImportContext->Bindings, RpcBinding));
}
RPC_STATUS RPC_ENTRY
RpcNsBindingImportDone(
IN RPC_NS_HANDLE *ImportContextIn
)
/*++
Routine Description:
Close an Import Context handle when done. Free up the current
Bindings vector, LookupContext and ImportContext structure.
Arguments:
ImportContext - handle to close.
Returns:
RPC_S_OK, RpcNsBindingLookupDone()
--*/
{
RPC_STATUS status;
PRPC_IMPORT_CONTEXT_P ImportContext;
ImportContext = (PRPC_IMPORT_CONTEXT_P) *ImportContextIn;
if (! ImportContext)
return(RPC_S_OK);
if (ImportContext->Bindings)
RpcBindingVectorFree(&ImportContext->Bindings);
status = RpcNsBindingLookupDone(&ImportContext->LookupContext);
I_RpcFree (ImportContext);
*ImportContextIn = 0;
return(status);
}
RPC_STATUS RPC_ENTRY
RpcNsMgmtHandleSetExpAge(
IN RPC_NS_HANDLE NsHandle,
IN unsigned long ExpirationAge
)
/*++
Routine Description:
Set the maxium age that a cached entry will be returned in reponse
to a name service inquirary transaction.
Arguments:
NsHandle - context handle created with one of the RpcNs*Begin APIs
Returns:
nsi_mgmt_handle_set_exp_age()
--*/
{
UNSIGNED16 NsiStatus;
RPC_NS_HANDLE LookupContext =
((PRPC_IMPORT_CONTEXT_P)NsHandle)->LookupContext;
RpcTryExcept
{
nsi_mgmt_handle_set_exp_age(LookupContext, ExpirationAge, &NsiStatus);
}
RpcExcept(1)
{
NsiStatus = MapException(RpcExceptionCode());
}
RpcEndExcept
return(NsiMapStatus(NsiStatus));
}
#define isLocalName(NetWorkAddress) (1) //BUGBUG
static RPC_STATUS
GetMatchingProtocols(
IN RPC_BINDING_VECTOR *BindingVector,
OUT MATCH_VECTOR *MatchVector,
IN char * SearchProtocol, OPTIONAL
IN int fLocalOnly
)
/*++
Routine Description:
Construct a match binding vector with protocols that we are interested in.
PERF: When we know how to parse NetWorkAddress to know when it is
a local name, we should select those first
Arguments:
BindingVector - vector of binding handles to select from.
MatchVector - place to put the results.
SearchProtocol - Protocol we are looking for. A Nil matches everything.
Returns:
The number of protocols that we matched in the match vector.
RPC_S_OK, RpcBindingToStringBinding(), RpcStringBindingParse()
--*/
{
RPC_STATUS Status;
unsigned int Index;
RT_CHAR * StringBinding, *ProtocolSeq, *NetAddress;
int fProtocolsMatched;
MatchVector->Count = 0;
for (Index = 0; Index < BindingVector->Count; Index++)
{
if (!BindingVector->BindingH[Index])
continue;
// Convert the binding handle to a string and then extract
// the fields we are interested in.
if (Status = RpcBindingToStringBinding(
BindingVector->BindingH[Index], &StringBinding))
return (Status);
if (Status = RpcStringBindingParse(StringBinding, 0,
&ProtocolSeq, &NetAddress, 0, 0))
return (Status);
fProtocolsMatched = 1;
if (SearchProtocol)
{
char * STmp = SearchProtocol;
for (RT_CHAR *pT = ProtocolSeq; *pT &&
(char) *pT++ == *STmp++; ) ;
if (*STmp)
fProtocolsMatched = 0;
}
// If we are looking for a local name only and the matched
// protocol isn't local, throw this one out.
if (fLocalOnly && !isLocalName(NetAddress))
fProtocolsMatched = 0;
// Return all the strings to the RPC runtime.
if (Status = RpcStringFree(&ProtocolSeq))
return(Status);
if (Status = RpcStringFree(&NetAddress))
return(Status);
if (Status = RpcStringFree(&StringBinding))
return(Status);
if (! fProtocolsMatched)
continue;
// A match is recorded as an index into the original vector.
MatchVector->IndexMatch[MatchVector->Count++] = Index;
}
return(RPC_S_OK);
}
int
RandomNumber(
)
/*++
Routine Description:
Yet another pseudo-random number generator.
Returns:
New random number, in the range 0..32767.
--*/
{
static long holdrand;
static int fInitialized = 0;
// Start with a different seed everytime.
if (!fInitialized)
{
fInitialized = 1;
// holdrand = clock();
}
return( (int) (holdrand = (long) ( (holdrand * 214013L + 2531011L)
>> 16 & 0x7fff ) ));
}
RPC_STATUS RPC_ENTRY
RpcNsBindingSelect(
IN OUT RPC_BINDING_VECTOR *BindingVector,
OUT RPC_BINDING_HANDLE __RPC_FAR * RpcBinding
)
/*++
Routine Description:
This function will select a Binding handle from a vector of binding
handles. Since we know a little bit about our binding handles, we
will chose the more effiecent types of handles first. We select
groups of bindings unordered via a random number generator.
Arguments:
BindingVector - vector of binding handles to select from
RpcBinding - place to return the binding handle. The ownership of
the handle passes to the caller.
Returns:
RPC_S_OK, RPC_S_OUT_OF_MEMORY, RPC_S_NO_MORE_BINDINGS, GetMatchingProtocols()
--*/
{
static char * PreferredProtocol[] =
{
"ncalrpc",
"ncacn_np",
0
};
int CountPreferredProtocol = sizeof(PreferredProtocol) / sizeof(void *);
RPC_STATUS Status;
MATCH_VECTOR *MatchVector;
int IndexSelected;
int ProtocolIndex;
int fLocalOnly;
*RpcBinding = 0;
MatchVector = (MATCH_VECTOR *) I_RpcAllocate((unsigned int)
(sizeof(MATCH_VECTOR) + sizeof(int) * BindingVector->Count));
if (!MatchVector)
return(RPC_S_OUT_OF_MEMORY);
// For all the protocols returned, first try the local ones, then
// the remote.
for (fLocalOnly = 1; fLocalOnly >= 0; fLocalOnly--)
{
for (ProtocolIndex = 0; ProtocolIndex < CountPreferredProtocol;
ProtocolIndex++)
{
// First, get the perferred protocols into a match vector.
// The match vector has a range from 0..number of matching protocols.
// We need this so we know what range to generate a random number.
if (Status = GetMatchingProtocols(BindingVector, MatchVector,
PreferredProtocol[ProtocolIndex], fLocalOnly))
return(Status);
// If we found any, select one and return it.
if (MatchVector->Count)
{
IndexSelected = MatchVector->
IndexMatch[RandomNumber() % MatchVector->Count];
*RpcBinding = BindingVector->BindingH[IndexSelected];
// Remove selected one from binding vector.
BindingVector->BindingH[IndexSelected] = 0;
I_RpcFree (MatchVector);
return(RPC_S_OK);
}
}
}
I_RpcFree (MatchVector);
return(RPC_S_NO_MORE_BINDINGS);
}
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupBeginA(
IN unsigned long EntryNameSyntax,
IN unsigned char __RPC_FAR * EntryName,
IN RPC_IF_HANDLE RpcIfSpec,
IN UUID __RPC_FAR * ObjUuid OPTIONAL,
IN unsigned long BindingMaxCount,
OUT RPC_NS_HANDLE *LookupContext
)
/*++
Routine Description:
This is an ASCII wrapper to the UNICODE version of the API. It
converts all char * -> short * strings and calls the UNICODE version.
--*/
{
WIDE_STRING EntryNameW(EntryName);
if (EntryNameW.OutOfMemory())
return(RPC_S_OUT_OF_MEMORY);
return(RpcNsBindingLookupBeginW(EntryNameSyntax, &EntryNameW,
RpcIfSpec, ObjUuid, BindingMaxCount, LookupContext));
}
RPC_STATUS RPC_ENTRY
RpcNsBindingImportBeginA(
IN unsigned long EntryNameSyntax,
IN unsigned char __RPC_FAR * EntryName,
IN RPC_IF_HANDLE RpcIfSpec,
IN UUID __RPC_FAR * ObjUuid OPTIONAL,
OUT RPC_NS_HANDLE *ImportContext
)
/*++
Routine Description:
This is an ASCII wrapper to the UNICODE version of the API. It
converts all char * -> short * strings and calls the UNICODE version.
--*/
{
WIDE_STRING EntryNameW(EntryName);
if (EntryNameW.OutOfMemory())
return(RPC_S_OUT_OF_MEMORY);
return(RpcNsBindingImportBeginW(EntryNameSyntax, &EntryNameW,
RpcIfSpec, ObjUuid, ImportContext));
}