|
|
/*++
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)); }
|