|
|
/*++
Copyright (C) Microsoft Corporation, 1991 - 1999
Module Name:
epclnt.cxx
Abstract:
This file contains the client runtime entry points into the endpoint mapper dll.
Author:
Michael Montague (mikemon) 06-Jan-1992
Revision History:
--*/ #include <precomp.hxx>
#include <epmp.h>
#include <epmap.h>
#include <twrproto.h>
#include <CharConv.hxx>
#include <OsfPcket.hxx>
#include <BitSet.hxx>
#include <ProtBind.hxx>
#include <OsfClnt.hxx>
extern RPC_STATUS __RPC_FAR MapFromNcaStatusCode ( IN unsigned long NcaStatus );
static ProtseqEndpointPair EpMapperTable[] =
{ "ncacn_np", "\\pipe\\epmapper", "ncalrpc", "epmapper", "ncacn_ip_tcp", "135", "ncadg_ip_udp", "135", #ifdef NETBIOS_ON
"ncacn_nb_nb", "135", "ncacn_nb_tcp", "135", "ncacn_nb_ipx", "135", #endif
#ifdef SPX_ON
"ncacn_spx", "34280", #endif
#ifdef IPX_ON
"ncadg_ipx", "34280", #endif
#ifdef APPLETALK_ON
"ncacn_at_dsp", "Endpoint Mapper", #endif
#ifdef NCADG_MQ_ON
"ncadg_mq", "EpMapper", #endif
"ncacn_http", "593" };
unsigned long PartialRetries=0; unsigned long ReallyTooBusy=0;
typedef struct _EP_LOOKUP_DATA { unsigned int NumberOfEndpoints; unsigned int MaximumEndpoints; unsigned int CurrentEndpoint; RPC_CHAR * PAPI * Endpoints; } EP_LOOKUP_DATA;
RPC_STATUS RPC_ENTRY EpResolveEndpoint ( IN UUID PAPI * ObjectUuid, OPTIONAL IN RPC_SYNTAX_IDENTIFIER PAPI * IfId, IN RPC_SYNTAX_IDENTIFIER PAPI * XferId, IN RPC_CHAR PAPI * RpcProtocolSequence, IN RPC_CHAR PAPI * NetworkAddress, IN RPC_CHAR PAPI * Options, IN OUT void PAPI * PAPI * EpLookupHandle, IN unsigned ConnTimeout, IN ULONG CallTimeout, IN CLIENT_AUTH_INFO *AuthInfo, OPTIONAL OUT RPC_CHAR * PAPI * Endpoint ) /*++
Routine Description:
The runtime will call this routine to resolve an endpoint.
Arguments:
ObjectUuid - Optional specifies the object uuid in the binding for which we are trying to resolve an endpoint.
Ifid - Pointer to the Syntax Identifier for the Interface
Xferid - Pointer to the Syntax Identifier for the Transfer Syntax.
RpcProtocolSequence - Supplies the rpc protocol sequence contained in the binding.
NetworkAddress - Supplies the network address. This will be used to contact the endpoint mapper on that machine in order to resolve the endpoint.
EpLookupHandle - Supplies the current version of the lookup handle for this iteration through the endpoint mapper. A new value for the lookup handle will be returned. If RPC_S_NO_ENDPOINT_FOUND is returned, this parameter will be set to its initial value, zero.
ConnTimeout - the connection timeout
CallTimeout - the call timeout
AutInfo - any auth info that needs to be used during the resolution process
Endpoint - Returns the endpoint resolved by the endpoint mapper on the machine specified by the network address argument. The storage for the endpoint must have been allocated using the runtime API I_RpcAllocate.
Return Value:
RPC_S_OK - The endpoint was successfully resolved.
EP_S_NOT_REGISTERED - There are no more endpoints to be found for the specified combination of interface, network address, and lookup handle.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allow resolution of the endpoint.
EP_S_CANT_PERFORM_OP - The operation failed due to misc. error e.g. unable to bind to the EpMapper.
--*/ { RPC_BINDING_HANDLE MapperHandle; RPC_STATUS RpcStatus; twr_p_t InputTower = 0; twr_p_t OutputTower[4]; unsigned long Returned; error_status ErrorStatus; ept_lookup_handle_t ContextHandle = 0; EP_LOOKUP_DATA PAPI * EpLookupData = (EP_LOOKUP_DATA PAPI *) *EpLookupHandle; unsigned long RetryCount, i; unsigned char PAPI * EPoint;
CHeapAnsi AnsiNWAddr, AnsiOptions; CStackAnsi AnsiProtseq; CNlUnicode nlEndpoint;
ASSERT(*Endpoint == 0);
// We have already taken all of the endpoints from the endpoint mapper;
// now we just return them back to the runtime one at a time.
ReturnEndpointFromList:
if ( EpLookupData != 0 ) {
// When we reach the end of the list of endpoints, return an error,
// and set things up so that we will start at the beginning again.
if ( EpLookupData->CurrentEndpoint == EpLookupData->NumberOfEndpoints ) { RpcpErrorAddRecord(EEInfoGCRuntime, EPT_S_NOT_REGISTERED, EEInfoDLEpResolveEndpoint10, RpcProtocolSequence, NetworkAddress, IfId->SyntaxGUID.Data1, (ULONG)((EpLookupData->CurrentEndpoint << 16) | EpLookupData->NumberOfEndpoints)); EpLookupData->CurrentEndpoint = 0; return(EPT_S_NOT_REGISTERED); }
*Endpoint = DuplicateString( EpLookupData->Endpoints[EpLookupData->CurrentEndpoint]); EpLookupData->CurrentEndpoint += 1;
if ( *Endpoint == 0 ) { return(RPC_S_OUT_OF_MEMORY); }
return(RPC_S_OK); }
// Otherwise, we need to take the list of endpoints from the endpoint
// mapper.
EpLookupData = (EP_LOOKUP_DATA PAPI *) RpcpFarAllocate( sizeof(EP_LOOKUP_DATA)); if ( EpLookupData == 0 ) { return(RPC_S_OUT_OF_MEMORY); } EpLookupData->MaximumEndpoints = 64; EpLookupData->Endpoints = (RPC_CHAR * PAPI *) RpcpFarAllocate( sizeof(RPC_CHAR PAPI *) * EpLookupData->MaximumEndpoints); if ( EpLookupData->Endpoints == 0 ) { RpcpFarFree(EpLookupData); EpLookupData = 0; return(RPC_S_OUT_OF_MEMORY); } EpLookupData->NumberOfEndpoints = 0; EpLookupData->CurrentEndpoint = 0;
RpcStatus = AnsiNWAddr.Attach(NetworkAddress); if ( RpcStatus != RPC_S_OK ) { ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY ); RpcpFarFree(EpLookupData); EpLookupData = 0; return(RpcStatus); }
i = 1+RpcpStringLength(RpcProtocolSequence); *(AnsiProtseq.GetPAnsiString()) = (char *)_alloca(i); RpcStatus = AnsiProtseq.Attach(RpcProtocolSequence, i, i * 2); if ( RpcStatus != RPC_S_OK ) { ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY ); RpcpFarFree(EpLookupData); EpLookupData = 0; return(RpcStatus); }
RpcStatus = AnsiOptions.Attach(Options); if ( RpcStatus != RPC_S_OK ) { ASSERT( RpcStatus == RPC_S_OUT_OF_MEMORY ); RpcpFarFree(EpLookupData); EpLookupData = 0; return(RpcStatus); }
RpcStatus = BindToEpMapper(&MapperHandle, NetworkAddress, RpcProtocolSequence, Options, ConnTimeout, CallTimeout, AuthInfo );
if ( RpcStatus != RPC_S_OK ) { MapperHandle = 0; goto CleanupAndReturn; }
RpcStatus = TowerConstruct((RPC_IF_ID PAPI *) IfId, (RPC_TRANSFER_SYNTAX PAPI *) XferId, (char PAPI *) AnsiProtseq, NULL, (char PAPI *) AnsiNWAddr, &InputTower); if ( RpcStatus != RPC_S_OK ) { goto CleanupAndReturn; }
for (RetryCount = 0;;) {
OutputTower[0] = 0; OutputTower[1] = 0; OutputTower[2] = 0; OutputTower[3] = 0;
RpcTryExcept { ept_map(MapperHandle, ObjectUuid, InputTower, &ContextHandle, 4L, &Returned, &OutputTower[0], &ErrorStatus); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { ErrorStatus = RpcExceptionCode(); } RpcEndExcept
if ( ErrorStatus == RPC_S_SERVER_TOO_BUSY) { if (RetryCount < 3) { RetryCount ++; PartialRetries++; continue; } else { ReallyTooBusy++; }
}
if ( ErrorStatus != 0 ) { // For DCE interop the endpoint mapper returns DCE errors on the
// wire. We need to map some of them to the MS RPC ones.
switch (ErrorStatus) { case EP_S_CANT_PERFORM_OP : RpcStatus = EPT_S_CANT_PERFORM_OP; break;
case EP_S_NOT_REGISTERED : RpcpErrorAddRecord(EEInfoGCRuntime, EPT_S_NOT_REGISTERED, EEInfoDLEpResolveEndpoint20, RpcProtocolSequence, NetworkAddress, IfId->SyntaxGUID.Data1, (ULONGLONG)MapperHandle); RpcStatus = EPT_S_NOT_REGISTERED; break;
default : RpcStatus = MapFromNcaStatusCode(ErrorStatus); break; }
break; }
ASSERT( ((Returned != 0) || (ContextHandle == 0)) && (Returned <= 4) );
for (i = 0; i < Returned; i++) { if (OutputTower[i] == 0) { return RPC_S_OUT_OF_MEMORY ; }
RpcStatus = TowerExplode( OutputTower[i], NULL, NULL, NULL, (char PAPI * PAPI *) &EPoint, NULL );
if ( RpcStatus != RPC_S_OK ) { break; }
RpcStatus = nlEndpoint.Attach((char *)EPoint); *Endpoint = nlEndpoint;
I_RpcFree(EPoint);
if ( *Endpoint == 0 ) { RpcStatus = RPC_S_OUT_OF_MEMORY; break; }
EpLookupData->Endpoints[EpLookupData->NumberOfEndpoints] = *Endpoint; EpLookupData->NumberOfEndpoints += 1; if ( EpLookupData->NumberOfEndpoints == EpLookupData->MaximumEndpoints ) { goto OutsideTheLoop; } }//..for Loop over parse all towers/eps in this loop
for (i = 0; i < Returned; i++) { MIDL_user_free(OutputTower[i]); }
if ( (ContextHandle == 0) || (RpcStatus != RPC_S_OK) ) { break; } } //..for loop over get all endpoints
OutsideTheLoop:
ASSERT( InputTower != 0 ); I_RpcFree(InputTower);
CleanupAndReturn:
if ( MapperHandle != 0 ) { RPC_STATUS Status = RpcBindingFree(&MapperHandle); ASSERT( Status == RPC_S_OK ); }
if ( ContextHandle != 0 ) { RpcSsDestroyClientContext(&ContextHandle); }
if ( ( RpcStatus == EPT_S_NOT_REGISTERED ) || ( RpcStatus == RPC_S_OK ) ) { if ( EpLookupData->NumberOfEndpoints != 0 ) { *EpLookupHandle = EpLookupData; goto ReturnEndpointFromList; } RpcStatus = EPT_S_NOT_REGISTERED; }
if ( EpLookupData != 0 ) { if ( EpLookupData->Endpoints != 0 ) { while ( EpLookupData->NumberOfEndpoints > 0 ) { EpLookupData->NumberOfEndpoints -= 1; delete EpLookupData->Endpoints[EpLookupData->NumberOfEndpoints]; } RpcpFarFree(EpLookupData->Endpoints); } RpcpFarFree(EpLookupData); }
return(RpcStatus); }
RPC_STATUS RPC_ENTRY EpGetEpmapperEndpoint( IN OUT RPC_CHAR * PAPI * Endpoint, IN RPC_CHAR PAPI * Protseq ) /*+
Routine Description:
Returns the Endpoint mappers well known endpoint for a given protocol sequence.
Arguments:
Endpoint - Place to store the epmappers well known endpoint.
Protsq - Protocol sequence the client wishes to use.
Return Value:
RPC_S_OK - Found the protocol sequence in the epmapper table and am returning the associated well known endpoint.
EPT_S_CANT_PERFORM_OP - Protocol sequence not found.
--*/
{ RPC_STATUS Status = EPT_S_CANT_PERFORM_OP; RPC_STATUS rc; unsigned int i, Count;
CStackAnsi AnsiProtseq; CNlUnicode nlEndpoint;
unsigned char PAPI * Epoint;
if (Protseq != NULL) {
#ifdef UNICODE
//Must convert the protocol sequence into an ansi string from unicode
i = 1 + RpcpStringLength(Protseq); *(AnsiProtseq.GetPAnsiString()) = (char *)_alloca(i); rc = AnsiProtseq.Attach(Protseq, i, i * 2);
if ( rc != RPC_S_OK ) { ASSERT( rc == RPC_S_OUT_OF_MEMORY ); return(Status); }
#else
AnsiProtseq = Protseq;
#endif
Count = sizeof(EpMapperTable)/sizeof(EpMapperTable[0]);
for (i = 0; i < Count; i++) {
//Search for the protocol sequence client is using.
if ( RpcpStringCompareA((char PAPI *)AnsiProtseq, (char PAPI *)EpMapperTable[i].Protseq) ) {
//Not yet found.
continue;
} else {
//Found a match. Grab the epmappers known endpoint.
Epoint = (unsigned char __RPC_FAR *)(EpMapperTable[i].Endpoint);
rc = nlEndpoint.Attach((char *)Epoint); *Endpoint = nlEndpoint;
Status = RPC_S_OK; break;
} } //for
}//if
return(Status);
}
RPC_STATUS RPC_ENTRY BindToEpMapper( OUT RPC_BINDING_HANDLE PAPI * MapperHandle, IN RPC_CHAR * NWAddress OPTIONAL, IN RPC_CHAR * Protseq OPTIONAL, IN RPC_CHAR * Options OPTIONAL, IN unsigned ConnTimeout, IN ULONG CallTimeout, IN CLIENT_AUTH_INFO *AuthInfo OPTIONAL ) /*+
Routine Description:
This helper routine is used to by RpcEpRegister[NoReplace], RpcEpUnRegister and EpResolveEndpoint(epclnt.cxx) to bind to the EpMapper. If a Protseq is supplied, that particular protseq is tried, otherwise lrpc is used to connect to the local epmapper. If a NW Address is specified EpMapper at that host is contacted, else local Endpoint mapper is used.
Arguments:
MapperHandle- Returns binding handle to the Endpoint mapper
NWAddress - NW address of the Endpoint mapper to bind to. Ignored if protseq is NULL.
Protseq - Protocol sequence the client wishes to use. NULL indicates a call to the local endpoint mapper.
ConnTimeout - the connection timeout
CallTimeout - the call timeout
AuthInfo - authentication information for the resolution
Return Value:
RPC_S_OK - The ansi string was successfully converted into a unicode string.
RPC_S_OUT_OF_MEMORY - Insufficient memory is available for the unicode string.
EP_S_CANT_PERFORM_OP - The binding was unsuccessful, possibly because the protocol sequence is not supported.
--*/ { RPC_STATUS Status = EPT_S_CANT_PERFORM_OP; RPC_CHAR * BindingString = NULL; unsigned int i, Count; BOOL fHttp = FALSE;
Count = sizeof(EpMapperTable)/sizeof(EpMapperTable[0]);
// If Protseq == NULL use lrpc.
if (NULL == Protseq) { ASSERT(NWAddress == 0); BindingString = RPC_STRING_LITERAL("ncalrpc:[epmapper]"); } else { char * AnsiProtseq;
AnsiProtseq = (char *) _alloca(1+RpcpStringLength(Protseq)); if (!AnsiProtseq) { return RPC_S_OUT_OF_MEMORY; }
SimpleUnicodeToAnsi(Protseq, AnsiProtseq);
if (Options) { fHttp = (0 == RpcpStringCompare(Protseq, RPC_STRING_LITERAL("ncacn_http"))); }
for (i = 0; i < Count; i++) { if (RpcpStringCompareA(AnsiProtseq, (char PAPI *) EpMapperTable[i].Protseq) ) continue;
// Found it.
RPC_CHAR * Endpoint;
Endpoint = (RPC_CHAR *) _alloca(sizeof(RPC_CHAR) * (1+strlen(EpMapperTable[i].Endpoint))); if (!Endpoint) { return RPC_S_OUT_OF_MEMORY; }
SimpleAnsiToPlatform(EpMapperTable[i].Endpoint, Endpoint);
Status = RpcStringBindingCompose( NULL, Protseq, NWAddress, Endpoint, (fHttp ? Options : 0), &BindingString); break; } }
if (BindingString) { Status = RpcBindingFromStringBinding(BindingString, MapperHandle); }
if (BindingString != NULL && Protseq != NULL) { RpcStringFree(&BindingString); }
if (Status != RPC_S_OK) { return(EPT_S_CANT_PERFORM_OP); }
if (AuthInfo && (RpcpStringNCompare(Protseq, RPC_STRING_LITERAL("ncacn_"), 6) == 0)) { Status = SetAuthInformation (*MapperHandle, AuthInfo);
if (Status != RPC_S_OK) return Status; }
Status = RpcMgmtSetComTimeout(*MapperHandle, ConnTimeout);
if (Status != RPC_S_OK) { return(EPT_S_CANT_PERFORM_OP); }
return(RPC_S_OK); }
void RPC_ENTRY EpFreeLookupHandle ( IN void PAPI * EpLookupHandle ) { EP_LOOKUP_DATA PAPI * EpLookupData = (EP_LOOKUP_DATA PAPI *) EpLookupHandle;
if ( EpLookupData->Endpoints != 0 ) { while ( EpLookupData->NumberOfEndpoints > 0 ) { EpLookupData->NumberOfEndpoints -= 1; delete EpLookupData->Endpoints[EpLookupData->NumberOfEndpoints]; } RpcpFarFree(EpLookupData->Endpoints); } RpcpFarFree(EpLookupData); }
HPROCESS hRpcssContext = 0;
RPC_STATUS RPC_ENTRY I_RpcServerAllocateIpPort( IN DWORD Flags, OUT USHORT *pPort ) { USHORT Port; RPC_STATUS status; RPC_BINDING_HANDLE hServer; PORT_TYPE type;
*pPort = 0;
// Figure out what sort of port to allocate
if (Flags & RPC_C_USE_INTERNET_PORT) { type = PORT_INTERNET; Flags &= ~RPC_C_USE_INTERNET_PORT; } else if (Flags & RPC_C_USE_INTRANET_PORT) { type = PORT_INTRANET; Flags &= ~RPC_C_USE_INTRANET_PORT; } else { type = PORT_DEFAULT; }
// Setup process context in the endpoint mapper if needed.
if (hRpcssContext == 0) { HPROCESS hProcess;
status = RpcBindingFromStringBinding(RPC_STRING_LITERAL("ncalrpc:[epmapper]"), &hServer); if (status != RPC_S_OK) { return(status); }
hProcess = 0;
status = OpenEndpointMapper(hServer, &hProcess);
RPC_STATUS statust = RpcBindingFree(&hServer); ASSERT(statust == RPC_S_OK);
if (status != RPC_S_OK) { return(status); }
GlobalMutexRequest();
if (hRpcssContext != 0) { ASSERT(hRpcssContext != hProcess); RpcSmDestroyClientContext(&hProcess); } else { hRpcssContext = hProcess; }
GlobalMutexClear(); }
// Actually allocate a port.
RPC_STATUS allocstatus;
status = AllocateReservedIPPort(hRpcssContext, type, &allocstatus, pPort);
if (status != RPC_S_OK) { ASSERT(*pPort == 0); return(status); }
return(allocstatus); }
// Very special code for our older (NT 3.1 Era) servers.
//
// These server send out unique pointers which will confuse our
// stubs while unmarshalling. Here we go through and fixup the
// node id's to look like full pointers.
//
// This code can be removed when support for NT 3.1 era servers
// is no longer required.
extern "C" void FixupForUniquePointerServers(PRPC_MESSAGE pMessage) { int CurrentPointer = 3; unsigned int NumberOfPointers; unsigned int i; unsigned long __RPC_FAR *pBuffer;
pBuffer = (unsigned long __RPC_FAR *) pMessage->Buffer;
// The output buffer looks like:
// [ out-context handle (20b) ]
// [ count (4b) ]
// [ max (4b) ]
// [ min (4b) ]
// [ length (4b) ] // should be the same as count
// [ pointer node (count of them) ]
ASSERT(pBuffer[5] == pBuffer[8]);
NumberOfPointers = pBuffer[5];
ASSERT(pMessage->BufferLength >= 4 * 9 + 4 * NumberOfPointers);
for(i = 0; i < NumberOfPointers; i++) { if (pBuffer[9 + i] != 0) { pBuffer[9 + i] = CurrentPointer; CurrentPointer++; } }
return; }
#if defined(WIN) || defined(WIN32)
void __RPC_FAR * __RPC_API MIDL_user_allocate( size_t Size ) /*++
Routine Description:
MIDL generated stubs need this routine.
Arguments:
Size - Supplies the length of the memory to allocate in bytes.
Return Value:
The buffer allocated will be returned, if there is sufficient memory, otherwise, zero will be returned.
--*/ { void PAPI * pvBuf;
pvBuf = I_RpcAllocate(Size);
return(pvBuf); }
void __RPC_API MIDL_user_free ( void __RPC_FAR *Buf ) {
I_RpcFree(Buf);
}
#endif
|