5405 lines
144 KiB
C++
5405 lines
144 KiB
C++
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Microsoft Windows
|
|||
|
//
|
|||
|
// Copyright (C) Microsoft Corporation, 1990 - 1999
|
|||
|
//
|
|||
|
// File: hndlsvr.cxx
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
/* --------------------------------------------------------------------
|
|||
|
|
|||
|
Microsoft OS/2 LAN Manager
|
|||
|
Copyright(c) Microsoft Corp., 1990
|
|||
|
|
|||
|
-------------------------------------------------------------------- */
|
|||
|
/* --------------------------------------------------------------------
|
|||
|
|
|||
|
File : hndlsvr.cxx
|
|||
|
|
|||
|
Description :
|
|||
|
|
|||
|
This file contains the implementations of the classes defined in hndlsvr.hxx.
|
|||
|
These routines are independent of the actual RPC protocol / transport layer.
|
|||
|
In addition, these routines are also independent of the specific operating
|
|||
|
system in use.
|
|||
|
|
|||
|
History :
|
|||
|
|
|||
|
mikemon ??-??-?? Beginning of recorded history.
|
|||
|
mikemon 10-15-90 Changed the shutdown functionality to PauseExecution
|
|||
|
rather than suspending and resuming a thread.
|
|||
|
mikemon 12-28-90 Updated the comments to match reality.
|
|||
|
connieh 17-Feb-94 Created RPC_SERVER::RegisterRpcForwardFunction
|
|||
|
Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
|
|||
|
|
|||
|
-------------------------------------------------------------------- */
|
|||
|
|
|||
|
#include <precomp.hxx>
|
|||
|
#include <queue.hxx>
|
|||
|
#include <hndlsvr.hxx>
|
|||
|
#include <svrbind.hxx>
|
|||
|
#include <thrdctx.hxx>
|
|||
|
#include <rpcobj.hxx>
|
|||
|
#include <rpccfg.h>
|
|||
|
#include <sdict2.hxx>
|
|||
|
#include <dispatch.h>
|
|||
|
|
|||
|
#include <queue.hxx>
|
|||
|
#include <lpcpack.hxx>
|
|||
|
#include <lpcsvr.hxx>
|
|||
|
extern LRPC_SERVER *GlobalLrpcServer ;
|
|||
|
|
|||
|
#include <ProtBind.hxx>
|
|||
|
#include <osfpcket.hxx>
|
|||
|
#include <bitset.hxx>
|
|||
|
#include <osfclnt.hxx>
|
|||
|
#include <secsvr.hxx>
|
|||
|
#include <osfsvr.hxx>
|
|||
|
#include <dgpkt.hxx>
|
|||
|
#include <dgsvr.hxx>
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
DefaultCallbackFn (
|
|||
|
IN RPC_IF_HANDLE InterfaceUuid,
|
|||
|
IN void *Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:DefaultCallbackFn
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Returns:
|
|||
|
RPC_S_OK: Access is allowed
|
|||
|
other failures: Access is denied
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_CALL_ATTRIBUTES CallAttributes;
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
|
|||
|
CallAttributes.Flags = 0;
|
|||
|
|
|||
|
Status = RpcServerInqCallAttributesW(Context,
|
|||
|
&CallAttributes);
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
return Status;
|
|||
|
|
|||
|
if ((CallAttributes.AuthenticationService == RPC_C_AUTHN_NONE)
|
|||
|
|| (CallAttributes.AuthenticationLevel == RPC_C_AUTHN_LEVEL_NONE)
|
|||
|
|| (CallAttributes.NullSession)
|
|||
|
)
|
|||
|
{
|
|||
|
return RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_INTERFACE::RPC_INTERFACE (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN RPC_SERVER * Server,
|
|||
|
IN unsigned int Flags,
|
|||
|
IN unsigned int MaxCalls,
|
|||
|
IN unsigned int MaxRpcSize,
|
|||
|
IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn,
|
|||
|
OUT RPC_STATUS *Status
|
|||
|
) : NullManagerActiveCallCount(0), AutoListenCallCount(0)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
This method will get called to construct an instance of the
|
|||
|
RPC_INTERFACE class. We have got to make a copy of the rpc interface
|
|||
|
information supplied. The copy is necessary because we do not delete
|
|||
|
interfaces when they are unregistered. We just mark them as being
|
|||
|
inactive. In addition, we need to set the NullManagerFlag
|
|||
|
to zero, since this is used as the flag indicating whether we have
|
|||
|
got a manager for the NULL type UUID.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterfaceInformation - Supplies the rpc interface information
|
|||
|
which describes this interface.
|
|||
|
|
|||
|
Server - Supplies the rpc server which owns this rpc interface.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ALLOCATE_THIS(RPC_INTERFACE);
|
|||
|
unsigned int Length;
|
|||
|
|
|||
|
PipeInterfaceFlag = 0;
|
|||
|
SequenceNumber = 1;
|
|||
|
|
|||
|
#if DBG
|
|||
|
Strict = iuschDontKnow;
|
|||
|
#endif
|
|||
|
|
|||
|
if (RpcInterfaceInformation->Length > sizeof(RPC_SERVER_INTERFACE) )
|
|||
|
{
|
|||
|
Length = sizeof(RPC_SERVER_INTERFACE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Length = RpcInterfaceInformation->Length;
|
|||
|
}
|
|||
|
|
|||
|
if ((RpcInterfaceInformation->Length > NT351_INTERFACE_SIZE)
|
|||
|
&& (RpcInterfaceInformation->Flags & RPC_INTERFACE_HAS_PIPES))
|
|||
|
{
|
|||
|
PipeInterfaceFlag = 1;
|
|||
|
}
|
|||
|
|
|||
|
RpcpMemoryCopy(&(this->RpcInterfaceInformation), RpcInterfaceInformation, Length);
|
|||
|
|
|||
|
NullManagerFlag = 0;
|
|||
|
ManagerCount = 0;
|
|||
|
this->Server = Server;
|
|||
|
this->Flags = Flags ;
|
|||
|
this->MaxCalls = MaxCalls ;
|
|||
|
this->MaxRpcSize = MaxRpcSize;
|
|||
|
fBindingsExported = 0;
|
|||
|
UuidVector = NULL;
|
|||
|
|
|||
|
if (Flags & RPC_IF_ALLOW_SECURE_ONLY
|
|||
|
&& IfCallbackFn == NULL)
|
|||
|
{
|
|||
|
this->CallbackFn = DefaultCallbackFn;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this->CallbackFn = IfCallbackFn ;
|
|||
|
}
|
|||
|
|
|||
|
if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
|
|||
|
{
|
|||
|
*Status = NdrServerGetSupportedSyntaxes(RpcInterfaceInformation,
|
|||
|
&NumberOfSupportedTransferSyntaxes,
|
|||
|
&TransferSyntaxesArray, &PreferredTransferSyntax);
|
|||
|
if (*Status != RPC_S_OK)
|
|||
|
return;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NumberOfSupportedTransferSyntaxes = 0;
|
|||
|
}
|
|||
|
|
|||
|
*Status = RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::RegisterTypeManager (
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid OPTIONAL,
|
|||
|
IN RPC_MGR_EPV PAPI * ManagerEpv OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to register a type manager with this interface.
|
|||
|
If no type UUID is specified, or it is the NULL type UUID, we
|
|||
|
stick the manager entry point vector right in this instance (assuming
|
|||
|
that there is not already one), otherwise, we put it into the
|
|||
|
dictionary of interface manager objects.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ManagerTypeUuid - Optionally supplies the type UUID for the manager
|
|||
|
we want to register with this rpc interface. If no type UUID
|
|||
|
is supplied then the NULL type UUID is assumed.
|
|||
|
|
|||
|
ManagerEpv - Supplies then entry point vector for this manager. This
|
|||
|
vector is used to dispatch from the stub to the application
|
|||
|
code.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
RPC_S_OK - The type manager has been successfully added to this
|
|||
|
rpc interface.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is availabe to add the
|
|||
|
type manager to the rpc interface.
|
|||
|
|
|||
|
RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
|
|||
|
already been registered for the this interface under the
|
|||
|
specified manager type UUID.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE_MANAGER * InterfaceManager;
|
|||
|
|
|||
|
// First we need to check if the null UUID is being specified as
|
|||
|
// the type UUID; either, explicit or implicit by not specifying
|
|||
|
// a type UUID argument.
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
|
|||
|
if ( (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
|
|||
|
|| ( (ARGUMENT_PRESENT(ManagerTypeUuid) != 0)
|
|||
|
&& (ManagerTypeUuid->IsNullUuid() != 0)))
|
|||
|
{
|
|||
|
if (NullManagerFlag != 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_TYPE_ALREADY_REGISTERED);
|
|||
|
}
|
|||
|
|
|||
|
NullManagerEpv = ManagerEpv;
|
|||
|
NullManagerFlag = 1;
|
|||
|
ManagerCount += 1;
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
// If we reach here, a non-NULL type UUID is specified.
|
|||
|
|
|||
|
InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
|
|||
|
|
|||
|
if (InterfaceManager == 0)
|
|||
|
{
|
|||
|
InterfaceManager = new RPC_INTERFACE_MANAGER(ManagerTypeUuid,
|
|||
|
ManagerEpv);
|
|||
|
|
|||
|
if (InterfaceManager == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
if (InterfaceManagerDictionary.Insert(InterfaceManager) == -1)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
delete InterfaceManager;
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
ManagerCount += 1;
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
if (InterfaceManager->ValidManager() == 0)
|
|||
|
{
|
|||
|
InterfaceManager->SetManagerEpv(ManagerEpv);
|
|||
|
ManagerCount += 1;
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_TYPE_ALREADY_REGISTERED);
|
|||
|
}
|
|||
|
|
|||
|
RPC_INTERFACE_MANAGER *
|
|||
|
RPC_INTERFACE::FindInterfaceManager (
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to obtain the interface manager corresponding to
|
|||
|
the specified type UUID. The type UUID must not be the null UUID.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ManagerTypeUuid - Supplies the type UUID for which we are trying to
|
|||
|
find the interface manager.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If a interface manager for this type UUID is found, a pointer to it
|
|||
|
will be returned; otherwise, zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE_MANAGER * InterfaceManager;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
InterfaceManagerDictionary.Reset(cursor);
|
|||
|
while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if (InterfaceManager->MatchTypeUuid(ManagerTypeUuid) == 0)
|
|||
|
return(InterfaceManager);
|
|||
|
}
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::DispatchToStub (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN unsigned int CallbackFlag,
|
|||
|
IN PRPC_DISPATCH_TABLE DispatchTableToUse,
|
|||
|
OUT RPC_STATUS PAPI * ExceptionCode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to dispatch remote procedure calls to the
|
|||
|
appropriate stub and hence to the appropriate manager entry point.
|
|||
|
This routine is used for calls having a null UUID (implicit or
|
|||
|
explicit). We go to great pains to insure that we do not grab
|
|||
|
a mutex.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the response message and returns the reply
|
|||
|
message.
|
|||
|
|
|||
|
CallbackFlag - Supplies a flag indicating whether this is a callback
|
|||
|
or not. The argument will be zero if this is an original call,
|
|||
|
and non-zero if it is a callback.
|
|||
|
|
|||
|
ExceptionCode - Returns the exact exception code if an exception
|
|||
|
occurs.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - This value will be returned if the operation completed
|
|||
|
successfully.
|
|||
|
|
|||
|
RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
|
|||
|
too large, this value will be returned.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - If this interface does not exist, you will get this
|
|||
|
value back.
|
|||
|
|
|||
|
RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
|
|||
|
is not listening for remote procedure calls right now.
|
|||
|
|
|||
|
RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
|
|||
|
concurrent remote procedure calls for the rpc server which owns
|
|||
|
this interface.
|
|||
|
|
|||
|
RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
|
|||
|
ExceptionCode argument will contain the exception code for the
|
|||
|
fault.
|
|||
|
|
|||
|
RPC_S_UNSUPPORTED_TYPE - This interface exists, but does not have a manager
|
|||
|
for the null type.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|||
|
|
|||
|
if ( CallbackFlag == 0 )
|
|||
|
{
|
|||
|
NullManagerActiveCallCount.Increment();
|
|||
|
if ( NullManagerFlag == 0 )
|
|||
|
{
|
|||
|
NullManagerActiveCallCount.Decrement();
|
|||
|
|
|||
|
RpcStatus = RPC_S_UNSUPPORTED_TYPE;
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RpcStatus,
|
|||
|
EEInfoDLDispatchToStub10);
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
RpcStatus = RPC_S_UNKNOWN_IF;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RpcStatus,
|
|||
|
EEInfoDLDispatchToStub20);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
((MESSAGE_OBJECT *) Message->Handle)->FreeBuffer(Message);
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
|
|||
|
Message->ManagerEpv = NullManagerEpv;
|
|||
|
|
|||
|
RpcStatus = DispatchToStubWorker(Message, CallbackFlag, DispatchTableToUse, ExceptionCode);
|
|||
|
|
|||
|
if ( RpcStatus != RPC_S_OK
|
|||
|
|| (((MESSAGE_OBJECT *) Message->Handle)->IsSyncCall()
|
|||
|
&& CallbackFlag == 0 ))
|
|||
|
{
|
|||
|
NullManagerActiveCallCount.Decrement();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// DispatchToStubWorker freed Message.Buffer if an error occurred.
|
|||
|
//
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::DispatchToStubWorker (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN unsigned int CallbackFlag,
|
|||
|
IN PRPC_DISPATCH_TABLE DispatchTableToUse,
|
|||
|
OUT RPC_STATUS PAPI * ExceptionCode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to dispatch remote procedure calls to the
|
|||
|
appropriate stub and hence to the appropriate manager entry point.
|
|||
|
It will be used for calls with and without objects specified.
|
|||
|
We go to great pains to insure that we do not grab a mutex.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the response message and returns the reply
|
|||
|
message. If this routine returns anything other than RPC_S_OK
|
|||
|
Message->Buffer has already been freed.
|
|||
|
|
|||
|
CallbackFlag - Supplies a flag indicating whether this is a callback
|
|||
|
or not. The argument will be zero if this is an original call,
|
|||
|
and non-zero if it is a callback.
|
|||
|
|
|||
|
DispatchTableToUse - a pointer to the dispatch table to use. This is
|
|||
|
used to select b/n stubs for NDR20 and NDR64 transfer syntaxes
|
|||
|
|
|||
|
ExceptionCode - Returns the exact exception code if an exception
|
|||
|
occurs.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - This value will be returned if the operation completed
|
|||
|
successfully.
|
|||
|
|
|||
|
RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
|
|||
|
too large, this value will be returned.
|
|||
|
|
|||
|
RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
|
|||
|
is not listening for remote procedure calls right now.
|
|||
|
|
|||
|
RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
|
|||
|
concurrent remote procedure calls for the rpc server which owns
|
|||
|
this interface.
|
|||
|
|
|||
|
RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
|
|||
|
ExceptionCode argument will contain the exception code for the
|
|||
|
fault.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|||
|
void * OldServerContextList;
|
|||
|
unsigned int procnum ;
|
|||
|
THREAD *Self = RpcpGetThreadPointer() ;
|
|||
|
|
|||
|
ASSERT(Self);
|
|||
|
|
|||
|
if (Flags & RPC_IF_OLE)
|
|||
|
{
|
|||
|
procnum = 0 ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
procnum = Message->ProcNum ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (CallbackFlag == 0)
|
|||
|
{
|
|||
|
if (IsAutoListenInterface())
|
|||
|
{
|
|||
|
if (AutoListenCallCount.GetInteger() >= (long) MaxCalls)
|
|||
|
{
|
|||
|
RpcStatus = RPC_S_SERVER_TOO_BUSY ;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RpcStatus,
|
|||
|
EEInfoDLDispatchToStubWorker10,
|
|||
|
(ULONG)AutoListenCallCount.GetInteger(),
|
|||
|
(ULONG)MaxCalls);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (Server->IsServerListening() == 0)
|
|||
|
{
|
|||
|
RpcStatus = RPC_S_NOT_LISTENING;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RpcStatus,
|
|||
|
EEInfoDLDispatchToStubWorker20);
|
|||
|
}
|
|||
|
else if (Server->fAccountForMaxCalls && Server->CallBeginning() == 0)
|
|||
|
{
|
|||
|
RpcStatus = RPC_S_SERVER_TOO_BUSY;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RpcStatus,
|
|||
|
EEInfoDLDispatchToStubWorker30);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (procnum >=
|
|||
|
DispatchTableToUse->DispatchTableCount)
|
|||
|
{
|
|||
|
if (RpcStatus != RPC_S_SERVER_TOO_BUSY)
|
|||
|
{
|
|||
|
EndCall(CallbackFlag) ;
|
|||
|
}
|
|||
|
RpcStatus = RPC_S_PROCNUM_OUT_OF_RANGE;
|
|||
|
RpcpErrorAddRecord(EEInfoGCRuntime,
|
|||
|
RpcStatus,
|
|||
|
EEInfoDLDispatchToStubWorker40);
|
|||
|
}
|
|||
|
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
MO(Message)->FreeBuffer(Message);
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
|
|||
|
Server->IncomingCall();
|
|||
|
|
|||
|
((PRPC_RUNTIME_INFO) Message->ReservedForRuntime)->OldBuffer =
|
|||
|
Message->Buffer ;
|
|||
|
|
|||
|
Message->RpcInterfaceInformation = &RpcInterfaceInformation;
|
|||
|
SCALL(Message)->DoPreDispatchProcessing(Message, CallbackFlag);
|
|||
|
|
|||
|
if ( DispatchToStubInC(DispatchTableToUse->DispatchTable[procnum], Message, ExceptionCode) != 0 )
|
|||
|
{
|
|||
|
LogEvent(SU_EXCEPT, EV_STATUS, LongToPtr(*ExceptionCode),
|
|||
|
DispatchTableToUse->DispatchTable[procnum], (ULONG_PTR)Message, 1, 1);
|
|||
|
#if defined(DBG) && defined(i386)
|
|||
|
#if 1
|
|||
|
RtlCheckForOrphanedCriticalSections(NtCurrentThread());
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
RpcStatus = RPC_P_EXCEPTION_OCCURED;
|
|||
|
RpcpErrorAddRecord(EEInfoGCApplication,
|
|||
|
*ExceptionCode,
|
|||
|
EEInfoDLRaiseExc,
|
|||
|
GetInterfaceFirstDWORD(),
|
|||
|
(short)procnum,
|
|||
|
Message->RpcFlags,
|
|||
|
GetCurrentThreadId());
|
|||
|
}
|
|||
|
|
|||
|
RPC_MESSAGE OriginalMessage ;
|
|||
|
OriginalMessage.ReservedForRuntime = 0;
|
|||
|
OriginalMessage.Buffer =
|
|||
|
((PRPC_RUNTIME_INFO) Message->ReservedForRuntime)->OldBuffer;
|
|||
|
Self->ResetYield();
|
|||
|
|
|||
|
if (Self->IsSyncCall())
|
|||
|
{
|
|||
|
//
|
|||
|
// Since this is a sync call, we know that it has
|
|||
|
// not been freed yet. So we can safely touch it.
|
|||
|
//
|
|||
|
SCALL(Message)->DoPostDispatchProcessing();
|
|||
|
|
|||
|
//
|
|||
|
// The dispatched call was a sync call
|
|||
|
//
|
|||
|
if (RPC_S_OK == RpcStatus)
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// If the stub didn't allocate an output buffer, do so now.
|
|||
|
//
|
|||
|
if (OriginalMessage.Buffer == Message->Buffer)
|
|||
|
{
|
|||
|
Message->RpcFlags = 0;
|
|||
|
Message->BufferLength = 0;
|
|||
|
MO(Message)->GetBuffer(Message, 0);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the [in] buffer that we saved.
|
|||
|
//
|
|||
|
MO(Message)->FreeBuffer(&OriginalMessage);
|
|||
|
|
|||
|
EndCall(CallbackFlag) ;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ASSERT(RpcStatus == RPC_P_EXCEPTION_OCCURED) ;
|
|||
|
//
|
|||
|
// Free the buffer in the caller's message; this can be either
|
|||
|
// the [in] buffer or the [out] buffer, depending upon which
|
|||
|
// line of the stub caused the error.
|
|||
|
//
|
|||
|
// If the exception occurred after allocating the [out] buffer,
|
|||
|
// also free the [in] buffer.
|
|||
|
//
|
|||
|
if (OriginalMessage.Buffer != Message->Buffer)
|
|||
|
{
|
|||
|
MO(Message)->FreeBuffer(&OriginalMessage);
|
|||
|
}
|
|||
|
|
|||
|
if (Message->Buffer)
|
|||
|
{
|
|||
|
MO(Message)->FreeBuffer(Message);
|
|||
|
}
|
|||
|
|
|||
|
EndCall(CallbackFlag) ;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// The dispatched call was an async call
|
|||
|
//
|
|||
|
if (RpcStatus != RPC_S_OK
|
|||
|
&& OriginalMessage.Buffer != Message->Buffer)
|
|||
|
{
|
|||
|
//
|
|||
|
// The dispatch buffer will be freed during cleanup
|
|||
|
// of the async call
|
|||
|
//
|
|||
|
MO(Message)->FreeBuffer(Message);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RPC_INTERFACE::EndCall(
|
|||
|
IN unsigned int CallbackFlag,
|
|||
|
BOOL fAsync
|
|||
|
)
|
|||
|
{
|
|||
|
if (fAsync)
|
|||
|
{
|
|||
|
NullManagerActiveCallCount.Decrement();
|
|||
|
}
|
|||
|
|
|||
|
if (CallbackFlag == 0)
|
|||
|
{
|
|||
|
if (!(Flags & RPC_IF_AUTOLISTEN) && Server->fAccountForMaxCalls)
|
|||
|
{
|
|||
|
Server->CallEnding();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::DispatchToStubWithObject (
|
|||
|
IN OUT PRPC_MESSAGE Message,
|
|||
|
IN RPC_UUID * ObjectUuid,
|
|||
|
IN unsigned int CallbackFlag,
|
|||
|
IN PRPC_DISPATCH_TABLE DispatchTableToUse,
|
|||
|
OUT RPC_STATUS PAPI * ExceptionCode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to dispatch remote procedure calls to the
|
|||
|
appropriate stub and hence to the appropriate manager entry point.
|
|||
|
This routine is used for calls which have an associated object.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Message - Supplies the response message and returns the reply
|
|||
|
message.
|
|||
|
|
|||
|
ObjectUuid - Supplies the object uuid to map into the manager entry
|
|||
|
point for this call.
|
|||
|
|
|||
|
CallbackFlag - Supplies a flag indicating whether this is a callback
|
|||
|
or not. The argument will be zero if this is an original call,
|
|||
|
and non-zero if it is a callback.
|
|||
|
|
|||
|
ExceptionCode - Returns the exact exception code if an exception
|
|||
|
occurs.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The operation completed successfully.
|
|||
|
|
|||
|
RPC_S_PROCNUM_OUT_OF_RANGE - If the procedure number for this call is
|
|||
|
too large, this value will be returned.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - If the specified manager is no longer
|
|||
|
valid, you will get this value back.
|
|||
|
|
|||
|
RPC_S_NOT_LISTENING - The rpc server which owns this rpc interface
|
|||
|
is not listening for remote procedure calls right now.
|
|||
|
|
|||
|
RPC_S_SERVER_TOO_BUSY - This call will cause there to be too many
|
|||
|
concurrent remote procedure calls for the rpc server which owns
|
|||
|
this interface.
|
|||
|
|
|||
|
RPC_P_EXCEPTION_OCCURED - A fault occured, and we need to remote it. The
|
|||
|
ExceptionCode argument will contain the exception code for the
|
|||
|
fault.
|
|||
|
|
|||
|
RPC_S_UNSUPPORTED_TYPE - There is no type manager for the object's type
|
|||
|
for this interface.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_UUID TypeUuid;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
RPC_INTERFACE_MANAGER * RpcInterfaceManager;
|
|||
|
|
|||
|
RpcStatus = ObjectInqType(ObjectUuid, &TypeUuid);
|
|||
|
VALIDATE(RpcStatus)
|
|||
|
{
|
|||
|
RPC_S_OK,
|
|||
|
RPC_S_OBJECT_NOT_FOUND
|
|||
|
} END_VALIDATE;
|
|||
|
|
|||
|
if ( RpcStatus == RPC_S_OK )
|
|||
|
{
|
|||
|
RpcInterfaceManager = FindInterfaceManager(&TypeUuid);
|
|||
|
|
|||
|
if ( ( RpcInterfaceManager != 0 )
|
|||
|
&& ( ( CallbackFlag != 0 )
|
|||
|
|| ( RpcInterfaceManager->ValidManager() != 0 ) ) )
|
|||
|
{
|
|||
|
Message->ManagerEpv = RpcInterfaceManager->QueryManagerEpv();
|
|||
|
|
|||
|
if ( CallbackFlag == 0 )
|
|||
|
{
|
|||
|
RpcInterfaceManager->CallBeginning();
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = DispatchToStubWorker(Message, CallbackFlag, DispatchTableToUse,
|
|||
|
ExceptionCode);
|
|||
|
|
|||
|
if ( CallbackFlag == 0 )
|
|||
|
{
|
|||
|
RpcInterfaceManager->CallEnding();
|
|||
|
}
|
|||
|
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
if (this != GlobalManagementInterface)
|
|||
|
{
|
|||
|
// There is a type for this object, but no type manager for
|
|||
|
// this interface.
|
|||
|
|
|||
|
RpcStatus = RPC_S_UNSUPPORTED_TYPE;
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
RpcStatus = RPC_S_UNKNOWN_IF;
|
|||
|
}
|
|||
|
|
|||
|
((MESSAGE_OBJECT *) Message->Handle)->FreeBuffer(Message);
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// There has not been a type registered for this object, so we will
|
|||
|
// just go ahead and try and use the NULL type manager.
|
|||
|
|
|||
|
return(DispatchToStub(Message, CallbackFlag, DispatchTableToUse, ExceptionCode));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
RPC_INTERFACE::IsObjectSupported (
|
|||
|
IN RPC_UUID * ObjectUuid
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Determines whether the manager for the given object UUID is registered.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ObjectUuid - the client's object UUID
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK if it is OK to dispatch
|
|||
|
RPC_S_UNKNOWN_IF if the interface is not registered
|
|||
|
RPC_S_UNSUPPORTED_TYPE if this particular object's type is not registered
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
|
|||
|
if (ObjectUuid->IsNullUuid() )
|
|||
|
{
|
|||
|
if ( NullManagerFlag == 0 )
|
|||
|
{
|
|||
|
Status = RPC_S_UNSUPPORTED_TYPE;
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
Status = RPC_S_UNKNOWN_IF;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RPC_UUID TypeUuid;
|
|||
|
Status = ObjectInqType(ObjectUuid, &TypeUuid);
|
|||
|
if ( Status == RPC_S_OK )
|
|||
|
{
|
|||
|
RPC_INTERFACE_MANAGER * RpcInterfaceManager = 0;
|
|||
|
|
|||
|
RpcInterfaceManager = FindInterfaceManager(&TypeUuid);
|
|||
|
if (!RpcInterfaceManager ||
|
|||
|
!RpcInterfaceManager->ValidManager())
|
|||
|
{
|
|||
|
Status = RPC_S_UNSUPPORTED_TYPE;
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
Status = RPC_S_UNKNOWN_IF;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = RPC_S_OK;
|
|||
|
if ( NullManagerFlag == 0 )
|
|||
|
{
|
|||
|
Status = RPC_S_UNSUPPORTED_TYPE;
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
Status = RPC_S_UNKNOWN_IF;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::UpdateBindings (
|
|||
|
IN RPC_BINDING_VECTOR *BindingVector
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:UpdateEpMapperBindings
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
unsigned int Length;
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
NS_ENTRY *NsEntry;
|
|||
|
#endif
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
if (fBindingsExported)
|
|||
|
{
|
|||
|
Status = RegisterEntries(&RpcInterfaceInformation,
|
|||
|
BindingVector,
|
|||
|
UuidVector,
|
|||
|
(unsigned char *) Annotation,
|
|||
|
fReplace);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
// shortcut the common path and avoid taking and holding
|
|||
|
// unnecessarily the high contention global mutex
|
|||
|
if (NsEntries.Size() == 0)
|
|||
|
return RPC_S_OK;
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
NsEntries.Reset(cursor);
|
|||
|
while ((NsEntry = NsEntries.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// Actually update the locator bindings
|
|||
|
//
|
|||
|
Status = GlobalRpcServer->NsBindingUnexport(
|
|||
|
NsEntry->EntryNameSyntax,
|
|||
|
NsEntry->EntryName,
|
|||
|
&RpcInterfaceInformation);
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
Status = GlobalRpcServer->NsBindingExport(
|
|||
|
NsEntry->EntryNameSyntax,
|
|||
|
NsEntry->EntryName,
|
|||
|
&RpcInterfaceInformation,
|
|||
|
BindingVector);
|
|||
|
#if DBG
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
PrintToDebugger("RPC: Bindings were unexported, but could not re-export\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
ClearGlobalMutex();
|
|||
|
#endif
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::InterfaceExported (
|
|||
|
IN UUID_VECTOR *MyObjectUuidVector,
|
|||
|
IN unsigned char *MyAnnotation,
|
|||
|
IN BOOL MyfReplace
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:InterfaceExported
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
RpcEpRegister was called on this interface. We need to keep track
|
|||
|
of the parameters, so that if we get a PNP notification, we can update
|
|||
|
the bindings using there params
|
|||
|
|
|||
|
Returns:
|
|||
|
RPC_S_OK: things went fine
|
|||
|
RPC_S_OUT_OF_MEMORY: ran out of memory
|
|||
|
--*/
|
|||
|
{
|
|||
|
RequestGlobalMutex();
|
|||
|
|
|||
|
if (UuidVector
|
|||
|
&& UuidVector != MyObjectUuidVector)
|
|||
|
{
|
|||
|
RpcpFarFree(UuidVector);
|
|||
|
UuidVector = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (MyObjectUuidVector)
|
|||
|
{
|
|||
|
if (UuidVector != MyObjectUuidVector)
|
|||
|
{
|
|||
|
int Size = MyObjectUuidVector->Count*(sizeof(UUID)+sizeof(UUID *))
|
|||
|
+sizeof(unsigned long);
|
|||
|
UUID *Uuids;
|
|||
|
unsigned i;
|
|||
|
|
|||
|
UuidVector = (UUID_VECTOR *) RpcpFarAllocate(Size);
|
|||
|
if (UuidVector == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
Uuids = (UUID *) ((char *) UuidVector + sizeof(unsigned long)
|
|||
|
+(sizeof(UUID *) * MyObjectUuidVector->Count));
|
|||
|
|
|||
|
UuidVector->Count = MyObjectUuidVector->Count;
|
|||
|
|
|||
|
for (i = 0; i < UuidVector->Count; i++)
|
|||
|
{
|
|||
|
Uuids[i] = *(MyObjectUuidVector->Uuid[i]);
|
|||
|
UuidVector->Uuid[i] = &Uuids[i];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
UuidVector = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (MyAnnotation)
|
|||
|
{
|
|||
|
strncpy((char *) Annotation, (char *) MyAnnotation, 63);
|
|||
|
Annotation[63]=0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Annotation[0] = 0;
|
|||
|
}
|
|||
|
|
|||
|
fReplace = MyfReplace;
|
|||
|
fBindingsExported = 1;
|
|||
|
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
NS_ENTRY *
|
|||
|
RPC_INTERFACE::FindEntry (
|
|||
|
IN unsigned long EntryNameSyntax,
|
|||
|
IN RPC_CHAR *EntryName
|
|||
|
)
|
|||
|
{
|
|||
|
NS_ENTRY *NsEntry;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
//
|
|||
|
// This function will always be called with the mutex held
|
|||
|
//
|
|||
|
NsEntries.Reset(cursor);
|
|||
|
while ((NsEntry = NsEntries.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if (NsEntry->Match(EntryNameSyntax, EntryName))
|
|||
|
{
|
|||
|
return NsEntry;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::NsInterfaceUnexported (
|
|||
|
IN unsigned long EntryNameSyntax,
|
|||
|
IN RPC_CHAR *EntryName
|
|||
|
)
|
|||
|
{
|
|||
|
NS_ENTRY *NsEntry;
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
NsEntry = FindEntry(EntryNameSyntax, EntryName);
|
|||
|
if (NsEntry == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
#if DBG
|
|||
|
PrintToDebugger("RPC: No corresponding exported entry\n");
|
|||
|
#endif
|
|||
|
return RPC_S_ENTRY_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
NsEntries.Delete(NsEntry->Key);
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::NsInterfaceExported (
|
|||
|
IN unsigned long EntryNameSyntax,
|
|||
|
IN RPC_CHAR *EntryName
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
NS_ENTRY *NsEntry;
|
|||
|
int retval;
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
NsEntry = FindEntry(EntryNameSyntax, EntryName);
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
if (NsEntry)
|
|||
|
{
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
NsEntry = new NS_ENTRY(
|
|||
|
EntryNameSyntax,
|
|||
|
EntryName,
|
|||
|
&Status);
|
|||
|
if (NsEntry == 0)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete NsEntry;
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
NsEntry->Key = NsEntries.Insert(NsEntry);
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
if (NsEntry->Key == -1)
|
|||
|
{
|
|||
|
delete NsEntry;
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
static unsigned int
|
|||
|
MatchSyntaxIdentifiers (
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER ServerSyntax,
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER ClientSyntax
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method compares two syntax identifiers (which consist of a
|
|||
|
uuid, a major version number, and a minor version number). In
|
|||
|
order for the syntax identifiers to match, the uuids must be the
|
|||
|
same, the major version numbers must be the same, and the client
|
|||
|
minor version number must be less than or equal to the server
|
|||
|
minor version number.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerSyntax - Supplies the server syntax identifier.
|
|||
|
|
|||
|
ClientSyntax - Supplies the client syntax identifer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Zero will be returned if the client syntax identifier matches the
|
|||
|
server syntax identifier; otherwise, non-zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (RpcpMemoryCompare(&(ServerSyntax->SyntaxGUID),
|
|||
|
&(ClientSyntax->SyntaxGUID), sizeof(UUID)) != 0)
|
|||
|
return(1);
|
|||
|
if (ServerSyntax->SyntaxVersion.MajorVersion
|
|||
|
!= ClientSyntax->SyntaxVersion.MajorVersion)
|
|||
|
return(1);
|
|||
|
if (ServerSyntax->SyntaxVersion.MinorVersion
|
|||
|
< ClientSyntax->SyntaxVersion.MinorVersion)
|
|||
|
return(1);
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
unsigned int
|
|||
|
RPC_INTERFACE::MatchInterfaceIdentifier (
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method compares the supplied interface identifier (which consists
|
|||
|
of the interface uuid and interface version) against that contained
|
|||
|
in this rpc interface. In order for this rpc interface to match,
|
|||
|
the interface uuids must be the same, the interface major versions
|
|||
|
must be the same, and the supplied interface minor version must be
|
|||
|
less than or equal to the interface minor version contained in this
|
|||
|
rpc interface.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InterfaceIdentifier - Supplies the interface identifier to compare
|
|||
|
against that contained in this rpc interface.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Zero will be returned if the supplied interface identifer matches
|
|||
|
(according to the rules described above) the interface identifier
|
|||
|
contained in this rpc interface; otherwise, non-zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (ManagerCount == 0)
|
|||
|
return(1);
|
|||
|
|
|||
|
return(MatchSyntaxIdentifiers(&(RpcInterfaceInformation.InterfaceId),
|
|||
|
InterfaceIdentifier));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
unsigned int
|
|||
|
RPC_INTERFACE::SelectTransferSyntax (
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
|
|||
|
IN unsigned int NumberOfTransferSyntaxes,
|
|||
|
OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
|
|||
|
OUT BOOL *fIsInterfaceTransferPreferred,
|
|||
|
OUT int *ProposedTransferSyntaxIndex,
|
|||
|
OUT int *AvailableTransferSyntaxIndex
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to select a transfer syntax from a list of one
|
|||
|
or more transfer syntaxes. If a transfer syntax is selected, then
|
|||
|
it will be returned in one of the arguments.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ProposedTransferSyntaxes - Supplies a list of one or more transfer
|
|||
|
syntaxes from which this interface should select one which it
|
|||
|
supports if possible.
|
|||
|
|
|||
|
NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
|
|||
|
in the proposed transfer syntaxes argument.
|
|||
|
|
|||
|
AcceptedTransferSyntax - Returns the selected transfer syntax, if
|
|||
|
one is selected.
|
|||
|
|
|||
|
fIsInterfaceTransferPreferred - true if the selected transfer syntax
|
|||
|
is preferred by the server
|
|||
|
|
|||
|
ProposedTransferSyntaxIndex - the index of the transfer syntax that is
|
|||
|
chosen from the proposed transfer syntaxes array. Zero based.
|
|||
|
|
|||
|
AvailableTransferSyntaxIndex - the index of the transfer syntax that is
|
|||
|
chosen from the available transfer syntaxes in the interface. This
|
|||
|
value must be stored in the binding and retrieved when asking for the
|
|||
|
transfer syntax and dispatch table. Zero based.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Zero will be returned if a transfer syntax is selected; otherwise,
|
|||
|
non-zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
unsigned int ProposedIndex;
|
|||
|
unsigned int AvailableIndex;
|
|||
|
unsigned int NumberOfAvailableSyntaxes;
|
|||
|
BOOL fMultipleTranfserSyntaxesSelected;
|
|||
|
RPC_SYNTAX_IDENTIFIER *CurrentTransferSyntax;
|
|||
|
RPC_SYNTAX_IDENTIFIER *BackupTransferSyntax = NULL;
|
|||
|
int BackupProposedTransferSyntaxIndex;
|
|||
|
int BackupAvailableTransferSyntaxIndex;
|
|||
|
|
|||
|
fMultipleTranfserSyntaxesSelected = AreMultipleTransferSyntaxesSupported();
|
|||
|
if (fMultipleTranfserSyntaxesSelected)
|
|||
|
NumberOfAvailableSyntaxes = NumberOfSupportedTransferSyntaxes;
|
|||
|
else
|
|||
|
NumberOfAvailableSyntaxes = 1;
|
|||
|
|
|||
|
for (AvailableIndex = 0; AvailableIndex < NumberOfAvailableSyntaxes; AvailableIndex ++)
|
|||
|
{
|
|||
|
if (fMultipleTranfserSyntaxesSelected)
|
|||
|
CurrentTransferSyntax = &(TransferSyntaxesArray[AvailableIndex].TransferSyntax);
|
|||
|
else
|
|||
|
CurrentTransferSyntax = &RpcInterfaceInformation.TransferSyntax;
|
|||
|
for (ProposedIndex = 0; ProposedIndex < NumberOfTransferSyntaxes;
|
|||
|
ProposedIndex++)
|
|||
|
{
|
|||
|
if (MatchSyntaxIdentifiers(CurrentTransferSyntax,
|
|||
|
&(ProposedTransferSyntaxes[ProposedIndex])) == 0)
|
|||
|
{
|
|||
|
// is this the preferred transfer syntax for the server?
|
|||
|
if (AvailableIndex == PreferredTransferSyntax)
|
|||
|
{
|
|||
|
// this is the preferred transfer syntax - just
|
|||
|
// copy it and return
|
|||
|
RpcpMemoryCopy(AcceptedTransferSyntax,
|
|||
|
&(ProposedTransferSyntaxes[ProposedIndex]),
|
|||
|
sizeof(RPC_SYNTAX_IDENTIFIER));
|
|||
|
*fIsInterfaceTransferPreferred = TRUE;
|
|||
|
*ProposedTransferSyntaxIndex = ProposedIndex;
|
|||
|
*AvailableTransferSyntaxIndex = AvailableIndex;
|
|||
|
return(0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// this is not the preferred syntax - just remeber this
|
|||
|
// one (if no previous match was found) and continue
|
|||
|
if (BackupTransferSyntax == NULL)
|
|||
|
{
|
|||
|
BackupTransferSyntax = &(ProposedTransferSyntaxes[ProposedIndex]);
|
|||
|
BackupProposedTransferSyntaxIndex = ProposedIndex;
|
|||
|
BackupAvailableTransferSyntaxIndex = AvailableIndex;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// if we're here, this means we didn't find the preferred transfer syntax
|
|||
|
// check whether there is a backup syntax
|
|||
|
if (BackupTransferSyntax)
|
|||
|
{
|
|||
|
RpcpMemoryCopy(AcceptedTransferSyntax, BackupTransferSyntax,
|
|||
|
sizeof(RPC_SYNTAX_IDENTIFIER));
|
|||
|
*fIsInterfaceTransferPreferred = FALSE;
|
|||
|
*ProposedTransferSyntaxIndex = BackupProposedTransferSyntaxIndex;
|
|||
|
*AvailableTransferSyntaxIndex = BackupAvailableTransferSyntaxIndex;
|
|||
|
return(0);
|
|||
|
}
|
|||
|
// nada - no transfer syntax matches
|
|||
|
return(1);
|
|||
|
}
|
|||
|
|
|||
|
void RPC_INTERFACE::GetSelectedTransferSyntaxAndDispatchTable(IN int SelectedTransferSyntaxIndex,
|
|||
|
OUT RPC_SYNTAX_IDENTIFIER **SelectedTransferSyntax,
|
|||
|
OUT PRPC_DISPATCH_TABLE *SelectedDispatchTable)
|
|||
|
{
|
|||
|
MIDL_SYNTAX_INFO *SelectedSyntaxInfo;
|
|||
|
|
|||
|
if (DoesInterfaceSupportMultipleTransferSyntaxes(&RpcInterfaceInformation))
|
|||
|
{
|
|||
|
ASSERT((unsigned int)SelectedTransferSyntaxIndex <= NumberOfSupportedTransferSyntaxes);
|
|||
|
SelectedSyntaxInfo = &TransferSyntaxesArray[SelectedTransferSyntaxIndex];
|
|||
|
*SelectedTransferSyntax = &SelectedSyntaxInfo->TransferSyntax;
|
|||
|
// DCOM has only one dispatch table - they change the dispatch target
|
|||
|
// internally. They will define only the dispatch table in the
|
|||
|
// interface
|
|||
|
if (SelectedSyntaxInfo->DispatchTable)
|
|||
|
*SelectedDispatchTable = SelectedSyntaxInfo->DispatchTable;
|
|||
|
else
|
|||
|
*SelectedDispatchTable = GetDefaultDispatchTable();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*SelectedTransferSyntax = &RpcInterfaceInformation.TransferSyntax;
|
|||
|
*SelectedDispatchTable = GetDefaultDispatchTable();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::UnregisterManagerEpv (
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
|
|||
|
IN unsigned int WaitForCallsToComplete
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
In this method, we unregister one or all of the manager entry point
|
|||
|
vectors for this interface, depending on what, if anything, is
|
|||
|
specified for the manager type uuid argument.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ManagerTypeUuid - Optionally supplies the type uuid of the manager
|
|||
|
entry point vector to be removed. If this argument is not supplied,
|
|||
|
then all manager entry point vectors for this interface will
|
|||
|
be removed.
|
|||
|
|
|||
|
WaitForCallsToComplete - Supplies a flag indicating whether or not
|
|||
|
this routine should wait for all calls to complete using the
|
|||
|
interface and manager being unregistered. A non-zero value
|
|||
|
indicates to wait.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The manager entry point vector(s) are(were) successfully
|
|||
|
removed from the this interface.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
|
|||
|
with this interface.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - The specified interface is not registered with
|
|||
|
the rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE_MANAGER * InterfaceManager;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
if (ManagerCount == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_UNKNOWN_MGR_TYPE);
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
|
|||
|
{
|
|||
|
InterfaceManagerDictionary.Reset(cursor);
|
|||
|
while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
InterfaceManager->InvalidateManager();
|
|||
|
}
|
|||
|
|
|||
|
ManagerCount = 0;
|
|||
|
NullManagerFlag = 0;
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
if ( WaitForCallsToComplete != 0 )
|
|||
|
{
|
|||
|
while ( NullManagerActiveCallCount.GetInteger() > 0 )
|
|||
|
{
|
|||
|
PauseExecution(500L);
|
|||
|
}
|
|||
|
|
|||
|
InterfaceManagerDictionary.Reset(cursor);
|
|||
|
while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
while ( InterfaceManager->InquireActiveCallCount() > 0 )
|
|||
|
{
|
|||
|
PauseExecution(500L);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
if (ManagerTypeUuid->IsNullUuid() != 0)
|
|||
|
{
|
|||
|
if (NullManagerFlag == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_UNKNOWN_MGR_TYPE);
|
|||
|
}
|
|||
|
ManagerCount -= 1;
|
|||
|
NullManagerFlag = 0;
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
if ( WaitForCallsToComplete != 0 )
|
|||
|
{
|
|||
|
while ( NullManagerActiveCallCount.GetInteger() > 0 )
|
|||
|
{
|
|||
|
PauseExecution(500L);
|
|||
|
}
|
|||
|
}
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
|
|||
|
if ( (InterfaceManager == 0)
|
|||
|
|| (InterfaceManager->ValidManager() == 0))
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_UNKNOWN_MGR_TYPE);
|
|||
|
}
|
|||
|
InterfaceManager->InvalidateManager();
|
|||
|
ManagerCount -= 1;
|
|||
|
ClearGlobalMutex();
|
|||
|
|
|||
|
if ( WaitForCallsToComplete != 0 )
|
|||
|
{
|
|||
|
while ( InterfaceManager->InquireActiveCallCount() > 0 )
|
|||
|
{
|
|||
|
PauseExecution(500L);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::InquireManagerEpv (
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
|
|||
|
OUT RPC_MGR_EPV PAPI * PAPI * ManagerEpv
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to obtain the manager entry point vector
|
|||
|
with the specified type uuid supported by this interface.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ManagerTypeUuid - Optionally supplies the type uuid of the manager
|
|||
|
entry point vector we want returned. If no manager type uuid
|
|||
|
is specified, then the null uuid is assumed.
|
|||
|
|
|||
|
ManagerEpv - Returns the manager entry point vector.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The manager entry point vector has successfully been
|
|||
|
returned.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
|
|||
|
with the interface.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - The specified interface is not registered with
|
|||
|
the rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE_MANAGER * InterfaceManager;
|
|||
|
|
|||
|
RequestGlobalMutex();
|
|||
|
if (ManagerCount == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_UNKNOWN_IF);
|
|||
|
}
|
|||
|
|
|||
|
if ( (ARGUMENT_PRESENT(ManagerTypeUuid) == 0)
|
|||
|
|| (ManagerTypeUuid->IsNullUuid() != 0))
|
|||
|
{
|
|||
|
if (NullManagerFlag == 0)
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_UNKNOWN_MGR_TYPE);
|
|||
|
}
|
|||
|
|
|||
|
*ManagerEpv = NullManagerEpv;
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
InterfaceManager = FindInterfaceManager(ManagerTypeUuid);
|
|||
|
if ( (InterfaceManager == 0)
|
|||
|
|| (InterfaceManager->ValidManager() == 0))
|
|||
|
{
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_UNKNOWN_MGR_TYPE);
|
|||
|
}
|
|||
|
*ManagerEpv = InterfaceManager->QueryManagerEpv();
|
|||
|
ClearGlobalMutex();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::UpdateRpcInterfaceInformation (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN unsigned int Flags,
|
|||
|
IN unsigned int MaxCalls,
|
|||
|
IN unsigned int MaxRpcSize,
|
|||
|
IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We never delete the interface objects from a server; we just invalidate
|
|||
|
them. This means that if an interface has been complete unregistered
|
|||
|
(ie. it has no managers), we need to update the interface information
|
|||
|
again.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterfaceInformation - Supplies the interface information which this
|
|||
|
interface should be using.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
unsigned int Length;
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
Length = RpcInterfaceInformation->Length;
|
|||
|
|
|||
|
ASSERT((Length == sizeof(RPC_SERVER_INTERFACE)) ||
|
|||
|
(Length == NT351_INTERFACE_SIZE));
|
|||
|
|
|||
|
// make it stick on free builds as well
|
|||
|
if ((Length != sizeof(RPC_SERVER_INTERFACE)) &&
|
|||
|
(Length != NT351_INTERFACE_SIZE))
|
|||
|
return RPC_S_UNKNOWN_IF;
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
|
|||
|
{
|
|||
|
Status = NdrServerGetSupportedSyntaxes(RpcInterfaceInformation,
|
|||
|
&NumberOfSupportedTransferSyntaxes,
|
|||
|
&TransferSyntaxesArray, &PreferredTransferSyntax);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
return Status;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
NumberOfSupportedTransferSyntaxes = 0;
|
|||
|
}
|
|||
|
|
|||
|
RpcpMemoryCopy(&(this->RpcInterfaceInformation),
|
|||
|
RpcInterfaceInformation, Length);
|
|||
|
}
|
|||
|
|
|||
|
if (Flags & RPC_IF_AUTOLISTEN
|
|||
|
&& (this->Flags & RPC_IF_AUTOLISTEN) == 0)
|
|||
|
{
|
|||
|
GlobalRpcServer->IncrementAutoListenInterfaceCount() ;
|
|||
|
}
|
|||
|
|
|||
|
this->Flags = Flags ;
|
|||
|
this->MaxCalls = MaxCalls ;
|
|||
|
this->MaxRpcSize = MaxRpcSize;
|
|||
|
SequenceNumber++ ;
|
|||
|
|
|||
|
if (Flags & RPC_IF_ALLOW_SECURE_ONLY
|
|||
|
&& IfCallbackFn == NULL)
|
|||
|
{
|
|||
|
this->CallbackFn = DefaultCallbackFn;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this->CallbackFn = IfCallbackFn ;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_IF_ID __RPC_FAR *
|
|||
|
RPC_INTERFACE::InquireInterfaceId (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If this interface is active, its interface id will be returned in a
|
|||
|
newly allocated chunk of memory; otherwise, zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_IF_ID __RPC_FAR * RpcIfId;
|
|||
|
|
|||
|
if ( ManagerCount == 0 )
|
|||
|
{
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
RpcIfId = (RPC_IF_ID __RPC_FAR *) RpcpFarAllocate(sizeof(RPC_IF_ID));
|
|||
|
if ( RpcIfId == 0 )
|
|||
|
{
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
RpcIfId->Uuid = RpcInterfaceInformation.InterfaceId.SyntaxGUID;
|
|||
|
RpcIfId->VersMajor =
|
|||
|
RpcInterfaceInformation.InterfaceId.SyntaxVersion.MajorVersion;
|
|||
|
RpcIfId->VersMinor =
|
|||
|
RpcInterfaceInformation.InterfaceId.SyntaxVersion.MinorVersion;
|
|||
|
return(RpcIfId);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_INTERFACE::CheckSecurityIfNecessary(
|
|||
|
IN void * Context
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// If manager count in non-zero, this interface is still registered
|
|||
|
// If it has been registered with a call back function, invoke the callback
|
|||
|
// function, else return success....
|
|||
|
|
|||
|
RPC_IF_ID RpcIfId;
|
|||
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|||
|
|
|||
|
|
|||
|
if (CallbackFn != 0)
|
|||
|
{
|
|||
|
RpcIfId.Uuid = RpcInterfaceInformation.InterfaceId.SyntaxGUID;
|
|||
|
RpcIfId.VersMajor =
|
|||
|
RpcInterfaceInformation.InterfaceId.SyntaxVersion.MajorVersion;
|
|||
|
RpcIfId.VersMinor =
|
|||
|
RpcInterfaceInformation.InterfaceId.SyntaxVersion.MinorVersion;
|
|||
|
|
|||
|
BeginAutoListenCall();
|
|||
|
if (ManagerCount == 0)
|
|||
|
{
|
|||
|
EndAutoListenCall();
|
|||
|
return (RPC_S_UNKNOWN_IF);
|
|||
|
}
|
|||
|
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcStatus = CallbackFn(&RpcIfId, Context);
|
|||
|
}
|
|||
|
RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
|
|||
|
{
|
|||
|
RpcStatus = RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
EndAutoListenCall();
|
|||
|
}
|
|||
|
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RPC_INTERFACE::WaitForCalls(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Waits for the completion of all the calls on a given interface.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DictionaryCursor cursor;
|
|||
|
RPC_INTERFACE_MANAGER * InterfaceManager;
|
|||
|
|
|||
|
while ( NullManagerActiveCallCount.GetInteger() > 0 )
|
|||
|
{
|
|||
|
PauseExecution(500L);
|
|||
|
}
|
|||
|
|
|||
|
InterfaceManagerDictionary.Reset(cursor);
|
|||
|
while ((InterfaceManager = InterfaceManagerDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
while ( InterfaceManager->InquireActiveCallCount() > 0 )
|
|||
|
{
|
|||
|
PauseExecution(500L);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_SERVER::RPC_SERVER (
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus
|
|||
|
) : AvailableCallCount(0),
|
|||
|
ServerMutex(RpcStatus,
|
|||
|
TRUE // pre-allocate semaphore
|
|||
|
),
|
|||
|
StopListeningEvent(RpcStatus),
|
|||
|
ThreadCacheMutex(RpcStatus,
|
|||
|
TRUE, // pre-allocate semaphore
|
|||
|
100
|
|||
|
),
|
|||
|
NumAutoListenInterfaces(0)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will get called to construct an instance of the
|
|||
|
RPC_SERVER class.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ALLOCATE_THIS(RPC_SERVER);
|
|||
|
|
|||
|
ServerListeningFlag = 0;
|
|||
|
ListeningThreadFlag = 0;
|
|||
|
WaitingThreadFlag = 0;
|
|||
|
MinimumCallThreads = 1;
|
|||
|
MaximumConcurrentCalls = 1;
|
|||
|
IncomingRpcCount = 0;
|
|||
|
OutgoingRpcCount = 0;
|
|||
|
ReceivedPacketCount = 0;
|
|||
|
SentPacketCount = 0;
|
|||
|
ThreadCache = 0;
|
|||
|
ListenStatusCode = RPC_S_OK;
|
|||
|
fAccountForMaxCalls = TRUE;
|
|||
|
|
|||
|
pRpcForwardFunction = (RPC_FORWARD_FUNCTION *)0;
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
pNsBindingExport = 0;
|
|||
|
pNsBindingUnexport = 0;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_INTERFACE *
|
|||
|
RPC_SERVER::FindInterface (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to find the rpc interface registered with this
|
|||
|
server which matches the supplied rpc interface information.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterfaceInformation - Supplies the rpc interface information
|
|||
|
identifying the rpc interface we are looking for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The rpc interface matching the supplied rpc interface information
|
|||
|
will be returned if it is found; otherwise, zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.VerifyOwned();
|
|||
|
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if (RpcInterface->MatchRpcInterfaceInformation(
|
|||
|
RpcInterfaceInformation) == 0)
|
|||
|
{
|
|||
|
return(RpcInterface);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// The management interface is implicitly registered in all servers.
|
|||
|
|
|||
|
if ( (GlobalManagementInterface)
|
|||
|
&& (GlobalManagementInterface->MatchRpcInterfaceInformation(
|
|||
|
RpcInterfaceInformation) == 0) )
|
|||
|
{
|
|||
|
return(GlobalManagementInterface);
|
|||
|
}
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
RPC_SERVER::AddInterface (
|
|||
|
IN RPC_INTERFACE * RpcInterface
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method will be used to all an rpc interface to the set of
|
|||
|
interfaces known about by this server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterface - Supplies the rpc interface to add to the set of
|
|||
|
interfaces.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Zero will be returned if the interface is successfully added to
|
|||
|
the set; otherwise, non-zero will be returned indicating that
|
|||
|
insufficient memory is available to complete the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (RpcInterfaceDictionary.Insert(RpcInterface) == -1)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(-1);
|
|||
|
}
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::FindInterfaceTransfer (
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier,
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
|
|||
|
IN unsigned int NumberOfTransferSyntaxes,
|
|||
|
OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
|
|||
|
OUT RPC_INTERFACE ** AcceptingRpcInterface,
|
|||
|
OUT BOOL *fInterfaceTransferIsPreferred,
|
|||
|
OUT int *ProposedTransferSyntaxIndex,
|
|||
|
OUT int *AvailableTransferSyntaxIndex
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to determine if a client bind request can be
|
|||
|
accepted or not. All we have got to do here is hand off to the
|
|||
|
server which owns this address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InterfaceIdentifier - Supplies the syntax identifier for the
|
|||
|
interface; this is the interface uuid and version.
|
|||
|
|
|||
|
ProposedTransferSyntaxes - Supplies a list of one or more transfer
|
|||
|
syntaxes which the client initiating the binding supports. The
|
|||
|
server should pick one of these which is supported by the
|
|||
|
interface.
|
|||
|
|
|||
|
NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
|
|||
|
specified in the proposed transfer syntaxes argument.
|
|||
|
|
|||
|
AcceptedTransferSyntax - Returns the transfer syntax which the
|
|||
|
server accepted.
|
|||
|
|
|||
|
AcceptingRpcInterface - Returns a pointer to the rpc interface found
|
|||
|
which supports the requested interface and one of the requested
|
|||
|
transfer syntaxes.
|
|||
|
|
|||
|
fInterfaceTransferIsPreferred - non zero if the interface transfer
|
|||
|
returned is preferred.
|
|||
|
|
|||
|
TransferSyntaxIndex - the index of the chosen transfer syntax in the
|
|||
|
ProposedTransferSyntaxesArray
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The requested interface exists and it supports at least
|
|||
|
one of the proposed transfer syntaxes. We are all set, now we
|
|||
|
can make remote procedure calls.
|
|||
|
|
|||
|
RPC_S_UNSUPPORTED_TRANSFER_SYNTAX - The requested interface exists,
|
|||
|
but it does not support any of the proposed transfer syntaxes.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - The requested interface is not supported
|
|||
|
by this rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
unsigned int InterfaceFound = 0;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if (RpcInterface->MatchInterfaceIdentifier(InterfaceIdentifier) == 0)
|
|||
|
{
|
|||
|
InterfaceFound = 1;
|
|||
|
if (RpcInterface->SelectTransferSyntax(ProposedTransferSyntaxes,
|
|||
|
NumberOfTransferSyntaxes, AcceptedTransferSyntax,
|
|||
|
fInterfaceTransferIsPreferred, ProposedTransferSyntaxIndex,
|
|||
|
AvailableTransferSyntaxIndex) == 0)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
*AcceptingRpcInterface = RpcInterface;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
// The management interface is implicitly registered in all servers.
|
|||
|
|
|||
|
if ( (GlobalManagementInterface)
|
|||
|
&& (GlobalManagementInterface->MatchInterfaceIdentifier(
|
|||
|
InterfaceIdentifier) == 0 ) )
|
|||
|
{
|
|||
|
InterfaceFound = 1;
|
|||
|
if (GlobalManagementInterface->SelectTransferSyntax(
|
|||
|
ProposedTransferSyntaxes, NumberOfTransferSyntaxes,
|
|||
|
AcceptedTransferSyntax, fInterfaceTransferIsPreferred,
|
|||
|
ProposedTransferSyntaxIndex, AvailableTransferSyntaxIndex) == 0)
|
|||
|
{
|
|||
|
*AcceptingRpcInterface = GlobalManagementInterface;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (InterfaceFound == 0)
|
|||
|
return(RPC_S_UNKNOWN_IF);
|
|||
|
|
|||
|
return(RPC_S_UNSUPPORTED_TRANS_SYN);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_INTERFACE *
|
|||
|
RPC_SERVER::FindInterface (
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The datagram protocol module will use this routine to find the interface
|
|||
|
with out worrying about the transfer syntax. Datagram RPC does not support
|
|||
|
more than a single transfer syntax.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InterfaceIdentifier - Supplies the identifier (UUID and version) of the
|
|||
|
interface we are trying to find.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the interface is found it will be returned; otherwise, zero will be
|
|||
|
returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
while ( (RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if ( RpcInterface->MatchInterfaceIdentifier(InterfaceIdentifier)
|
|||
|
== 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RpcInterface);
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
// The management interface is implicitly registered in all servers.
|
|||
|
|
|||
|
if ( (GlobalManagementInterface)
|
|||
|
&& (GlobalManagementInterface->MatchInterfaceIdentifier(
|
|||
|
InterfaceIdentifier) == 0) )
|
|||
|
{
|
|||
|
return(GlobalManagementInterface);
|
|||
|
}
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::ServerListen (
|
|||
|
IN unsigned int MinimumCallThreads,
|
|||
|
IN unsigned int MaximumConcurrentCalls,
|
|||
|
IN unsigned int DontWait
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is called to start this rpc server listening for remote
|
|||
|
procedure calls. We do not return until after StopServerListening
|
|||
|
has been called and all active calls complete, or an error occurs.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MinimumCallThreads - Supplies the minimum number of call threads
|
|||
|
which should be created to service remote procedure calls.
|
|||
|
|
|||
|
MaximumConcurrentCalls - Supplies the maximum concurrent calls this
|
|||
|
rpc server is willing to accept at one time.
|
|||
|
|
|||
|
DontWait - Supplies a flag indicating whether or not to wait until
|
|||
|
RpcMgmtStopServerListening has been called and all calls have
|
|||
|
completed. A non-zero value indicates not to wait.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Everything worked out in the end. All active calls
|
|||
|
completed successfully after RPC_SERVER::StopServerListening
|
|||
|
was called. No errors occured in the transports.
|
|||
|
|
|||
|
RPC_S_ALREADY_LISTENING - This rpc server is already listening.
|
|||
|
|
|||
|
RPC_S_NO_PROTSEQS_REGISTERED - No protocol sequences have been
|
|||
|
registered with this rpc server. As a consequence it is
|
|||
|
impossible for this rpc server to receive any remote procedure
|
|||
|
calls, hence, the error code.
|
|||
|
|
|||
|
RPC_S_MAX_CALLS_TOO_SMALL - MaximumConcurrentCalls is smaller than
|
|||
|
MinimumCallThreads or MaximumConcurrentCalls is zero.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_ADDRESS * RpcAddress;
|
|||
|
RPC_STATUS Status;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
if ( ( MaximumConcurrentCalls < MinimumCallThreads )
|
|||
|
|| ( MaximumConcurrentCalls == 0 ) )
|
|||
|
{
|
|||
|
return(RPC_S_MAX_CALLS_TOO_SMALL);
|
|||
|
}
|
|||
|
|
|||
|
if ( MaximumConcurrentCalls > 0x7FFFFFFF )
|
|||
|
{
|
|||
|
MaximumConcurrentCalls = 0x7FFFFFFF;
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
|
|||
|
if ( ListeningThreadFlag != 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_ALREADY_LISTENING);
|
|||
|
}
|
|||
|
|
|||
|
if ( RpcAddressDictionary.Size() == 0
|
|||
|
&& RpcDormantAddresses.IsQueueEmpty())
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_NO_PROTSEQS_REGISTERED);
|
|||
|
}
|
|||
|
|
|||
|
this->MaximumConcurrentCalls = MaximumConcurrentCalls;
|
|||
|
// if we are provided the default number, then we don't really care -
|
|||
|
// play for optimal performance
|
|||
|
if (MaximumConcurrentCalls == RPC_C_LISTEN_MAX_CALLS_DEFAULT)
|
|||
|
fAccountForMaxCalls = FALSE;
|
|||
|
this->MinimumCallThreads = MinimumCallThreads;
|
|||
|
AvailableCallCount.SetInteger( MaximumConcurrentCalls );
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
Status = RpcAddress->ServerStartingToListen(
|
|||
|
MinimumCallThreads,
|
|||
|
MaximumConcurrentCalls);
|
|||
|
if (Status)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
StopListeningEvent.Lower();
|
|||
|
ServerListeningFlag = 1;
|
|||
|
ListeningThreadFlag = 1;
|
|||
|
|
|||
|
if ( DontWait != 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
WaitingThreadFlag = 1;
|
|||
|
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
return(WaitForStopServerListening());
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::WaitForStopServerListening (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We wait for StopServerListening to be called and then for all active
|
|||
|
remote procedure calls to complete before returning.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Everything worked out in the end. All active calls
|
|||
|
completed successfully after RPC_SERVER::StopServerListening
|
|||
|
was called. No errors occured in the transports.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_ADDRESS * RpcAddress;
|
|||
|
DictionaryCursor cursor;
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
|
|||
|
StopListeningEvent.Wait();
|
|||
|
|
|||
|
if ( ListenStatusCode != RPC_S_OK )
|
|||
|
{
|
|||
|
ListeningThreadFlag = 0;
|
|||
|
return(ListenStatusCode);
|
|||
|
}
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
RpcAddress->ServerStoppedListening();
|
|||
|
}
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
RpcAddress->WaitForCalls();
|
|||
|
}
|
|||
|
|
|||
|
// Wait for calls on all interfaces to complete
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
RpcInterface->WaitForCalls();
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
WaitingThreadFlag = 0;
|
|||
|
ListeningThreadFlag = 0;
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::WaitServerListen (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine performs the wait that ServerListen normally performs
|
|||
|
when the DontWait flag is not set. An application must call this
|
|||
|
routine only after RpcServerListen has been called with the DontWait
|
|||
|
flag set. We do not return until RpcMgmtStopServerListening is called
|
|||
|
and all active remote procedure calls complete, or a fatal error occurs
|
|||
|
in the runtime.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Everything worked as expected. All active remote procedure
|
|||
|
calls have completed. It is now safe to exit this process.
|
|||
|
|
|||
|
RPC_S_ALREADY_LISTENING - Another thread has already called
|
|||
|
WaitServerListen and has not yet returned.
|
|||
|
|
|||
|
RPC_S_NOT_LISTENING - ServerListen has not yet been called.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ServerMutex.Request();
|
|||
|
if ( ListeningThreadFlag == 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_NOT_LISTENING);
|
|||
|
}
|
|||
|
|
|||
|
if ( WaitingThreadFlag != 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_ALREADY_LISTENING);
|
|||
|
}
|
|||
|
|
|||
|
WaitingThreadFlag = 1;
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
return(WaitForStopServerListening());
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RPC_SERVER::InquireStatistics (
|
|||
|
OUT RPC_STATS_VECTOR * Statistics
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to obtain the statistics for this rpc server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Statistics - Returns the statistics for this rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
Statistics->Stats[RPC_C_STATS_CALLS_IN] = IncomingRpcCount;
|
|||
|
Statistics->Stats[RPC_C_STATS_CALLS_OUT] = OutgoingRpcCount;
|
|||
|
Statistics->Stats[RPC_C_STATS_PKTS_IN] = ReceivedPacketCount;
|
|||
|
Statistics->Stats[RPC_C_STATS_PKTS_OUT] = SentPacketCount;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::StopServerListening (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is called to stop this rpc server from listening for
|
|||
|
more remote procedure calls. Active calls are allowed to complete
|
|||
|
(including callbacks). The thread which called ServerListen will
|
|||
|
return when all active calls complete.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The thread that called ServerListen has successfully been
|
|||
|
notified that it should shutdown.
|
|||
|
|
|||
|
RPC_S_NOT_LISTENING - There is no thread currently listening.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (ListeningThreadFlag == 0)
|
|||
|
return(RPC_S_NOT_LISTENING);
|
|||
|
|
|||
|
ListenStatusCode = RPC_S_OK;
|
|||
|
ServerListeningFlag = 0;
|
|||
|
StopListeningEvent.Raise();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::UseRpcProtocolSequence (
|
|||
|
IN RPC_CHAR PAPI * NetworkAddress,
|
|||
|
IN RPC_CHAR PAPI * RpcProtocolSequence,
|
|||
|
IN unsigned int PendingQueueSize,
|
|||
|
IN RPC_CHAR PAPI *Endpoint,
|
|||
|
IN void PAPI * SecurityDescriptor,
|
|||
|
IN unsigned long EndpointFlags,
|
|||
|
IN unsigned long NICFlags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is who does the work of creating new address (they
|
|||
|
are called protocol sequences in the DCE lingo) and adding them to
|
|||
|
this rpc server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcProtocolSequence - Supplies the rpc protocol sequence we wish
|
|||
|
to add to this rpc server.
|
|||
|
|
|||
|
PendingQueueSize - Supplies the size of the queue of pending
|
|||
|
requests which should be created by the transport. Some transports
|
|||
|
will not be able to make use of this value, while others will.
|
|||
|
|
|||
|
Endpoint - Optionally supplies an endpoint to be used for the new
|
|||
|
address. If an endpoint is not specified, then we will let
|
|||
|
the transport specify the endpoint.
|
|||
|
|
|||
|
SecurityDescriptor - Optionally supplies a security descriptor to
|
|||
|
be placed on the rpc protocol sequence (address) we are adding
|
|||
|
to this rpc server.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The requested rpc protocol sequence has been added to
|
|||
|
this rpc server.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to add the
|
|||
|
requested rpc protocol sequence to this rpc server.
|
|||
|
|
|||
|
RPC_S_PROTSEQ_NOT_SUPPORTED - The specified rpc protocol sequence
|
|||
|
is not supported (but it appears to be valid).
|
|||
|
|
|||
|
RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
|
|||
|
syntactically invalid.
|
|||
|
|
|||
|
RPC_S_DUPLICATE_ENDPOINT - The supplied endpoint has already been
|
|||
|
added to this rpc server.
|
|||
|
|
|||
|
RPC_S_INVALID_SECURITY_DESC - The supplied security descriptor is
|
|||
|
invalid.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
TRANS_INFO *ServerTransInfo ;
|
|||
|
RPC_STATUS Status;
|
|||
|
RPC_ADDRESS * RpcAddress;
|
|||
|
RPC_ADDRESS * Address;
|
|||
|
NETWORK_ADDRESS_VECTOR *pNetworkAddressVector;
|
|||
|
unsigned int StaticEndpointFlag;
|
|||
|
int Key;
|
|||
|
DictionaryCursor cursor;
|
|||
|
THREAD *ThisThread;
|
|||
|
|
|||
|
ThisThread = ThreadSelf();
|
|||
|
if (ThisThread == NULL)
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
|
|||
|
// remove old EEInfo
|
|||
|
RpcpPurgeEEInfo();
|
|||
|
|
|||
|
if (IsServerSideDebugInfoEnabled())
|
|||
|
{
|
|||
|
Status = InitializeServerSideCellHeapIfNecessary();
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if ( RpcpStringCompare(RpcProtocolSequence,
|
|||
|
RPC_CONST_STRING("ncalrpc")) == 0 )
|
|||
|
{
|
|||
|
RpcAddress = LrpcCreateRpcAddress();
|
|||
|
}
|
|||
|
else if ( RpcpStringNCompare(
|
|||
|
RPC_CONST_STRING("ncadg_"),
|
|||
|
RpcProtocolSequence,
|
|||
|
6) == 0)
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Just use the osf mapping...it simply calls the
|
|||
|
// protocol-independent ones.
|
|||
|
//
|
|||
|
|
|||
|
Status = OsfMapRpcProtocolSequence(1,
|
|||
|
RpcProtocolSequence,
|
|||
|
&ServerTransInfo);
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
RpcAddress = DgCreateRpcAddress(ServerTransInfo);
|
|||
|
}
|
|||
|
else if ( RpcpStringNCompare(
|
|||
|
RPC_CONST_STRING("ncacn_"),
|
|||
|
RpcProtocolSequence,
|
|||
|
6) == 0)
|
|||
|
{
|
|||
|
Status = OsfMapRpcProtocolSequence(1,
|
|||
|
RpcProtocolSequence,
|
|||
|
&ServerTransInfo);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
RpcAddress = OsfCreateRpcAddress(ServerTransInfo);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(RPC_S_PROTSEQ_NOT_SUPPORTED);
|
|||
|
}
|
|||
|
|
|||
|
if (RpcAddress == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(Endpoint))
|
|||
|
{
|
|||
|
ServerMutex.Request();
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if ( Address->SameEndpointAndProtocolSequence(
|
|||
|
NetworkAddress,
|
|||
|
RpcProtocolSequence,
|
|||
|
Endpoint) != 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
delete RpcAddress;
|
|||
|
return(RPC_S_DUPLICATE_ENDPOINT);
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
Endpoint = DuplicateString(Endpoint);
|
|||
|
if (Endpoint == 0)
|
|||
|
{
|
|||
|
delete RpcAddress;
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
StaticEndpointFlag = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// MACBUG:
|
|||
|
// We need to include this for Macintosh/Win95 also...
|
|||
|
//
|
|||
|
ServerMutex.Request() ;
|
|||
|
RpcAddressDictionary.Reset(cursor) ;
|
|||
|
while ((Address = RpcAddressDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if ( Address->SameProtocolSequence(NetworkAddress,
|
|||
|
RpcProtocolSequence) != 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
StaticEndpointFlag = 0;
|
|||
|
} // else
|
|||
|
|
|||
|
if (EndpointFlags & RPC_C_DONT_FAIL)
|
|||
|
{
|
|||
|
RpcAddress->PnpNotify();
|
|||
|
}
|
|||
|
|
|||
|
Status = RpcAddress->ServerSetupAddress(
|
|||
|
NetworkAddress,
|
|||
|
&Endpoint,
|
|||
|
PendingQueueSize,
|
|||
|
SecurityDescriptor,
|
|||
|
EndpointFlags,
|
|||
|
NICFlags,
|
|||
|
&pNetworkAddressVector);
|
|||
|
|
|||
|
if (Status == RPC_S_OK)
|
|||
|
{
|
|||
|
RPC_CHAR *MyNetworkAddress = NULL;
|
|||
|
|
|||
|
RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
|
|||
|
|
|||
|
if (RpcProtocolSequence == 0)
|
|||
|
{
|
|||
|
delete Endpoint;
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(NetworkAddress))
|
|||
|
{
|
|||
|
MyNetworkAddress = DuplicateString(NetworkAddress);
|
|||
|
if (MyNetworkAddress == 0)
|
|||
|
{
|
|||
|
delete Endpoint;
|
|||
|
delete RpcAddress;
|
|||
|
delete RpcProtocolSequence;
|
|||
|
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Status = RpcAddress->SetEndpointAndStuff(
|
|||
|
MyNetworkAddress,
|
|||
|
Endpoint,
|
|||
|
RpcProtocolSequence,
|
|||
|
this,
|
|||
|
StaticEndpointFlag,
|
|||
|
PendingQueueSize,
|
|||
|
SecurityDescriptor,
|
|||
|
EndpointFlags,
|
|||
|
NICFlags,
|
|||
|
pNetworkAddressVector);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (EndpointFlags & RPC_C_DONT_FAIL)
|
|||
|
{
|
|||
|
int retval;
|
|||
|
|
|||
|
RPC_CHAR *MyNetworkAddress = NULL;
|
|||
|
|
|||
|
RpcProtocolSequence = DuplicateString(RpcProtocolSequence);
|
|||
|
|
|||
|
if (RpcProtocolSequence == 0)
|
|||
|
{
|
|||
|
delete Endpoint;
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(NetworkAddress))
|
|||
|
{
|
|||
|
MyNetworkAddress = DuplicateString(NetworkAddress);
|
|||
|
if (MyNetworkAddress == 0)
|
|||
|
{
|
|||
|
delete Endpoint;
|
|||
|
delete RpcAddress;
|
|||
|
delete RpcProtocolSequence;
|
|||
|
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Status = RpcAddress->SetEndpointAndStuff(
|
|||
|
MyNetworkAddress,
|
|||
|
Endpoint,
|
|||
|
RpcProtocolSequence,
|
|||
|
this,
|
|||
|
StaticEndpointFlag,
|
|||
|
PendingQueueSize,
|
|||
|
SecurityDescriptor,
|
|||
|
EndpointFlags,
|
|||
|
NICFlags,
|
|||
|
NULL);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
delete Endpoint;
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
retval = RpcDormantAddresses.PutOnQueue(RpcAddress, 0);
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
if (retval == 1)
|
|||
|
{
|
|||
|
delete Endpoint;
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
Status = RpcAddress->ServerStartingToListen(
|
|||
|
MinimumCallThreads,
|
|||
|
MaximumConcurrentCalls);
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
if (Status)
|
|||
|
{
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Key = AddAddress(RpcAddress);
|
|||
|
if (Key == -1)
|
|||
|
{
|
|||
|
delete RpcAddress;
|
|||
|
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
RpcAddress->DictKey = Key;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
Status = RpcAddress->ServerStartingToListen(
|
|||
|
MinimumCallThreads,
|
|||
|
MaximumConcurrentCalls);
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
if (Status)
|
|||
|
{
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Inform the transport that it can start.
|
|||
|
//
|
|||
|
RpcAddress->CompleteListen() ;
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
RPC_SERVER::AddAddress (
|
|||
|
IN RPC_ADDRESS * RpcAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to add an rpc address to the dictionary of
|
|||
|
rpc addresses know about by this rpc server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcAddress - Supplies the rpc address to be inserted into the
|
|||
|
dictionary of rpc addresses.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The supplied rpc address has been successfully added
|
|||
|
to the dictionary.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to insert
|
|||
|
the rpc address into the dictionary.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int Key;
|
|||
|
ServerMutex.Request();
|
|||
|
Key = RpcAddressDictionary.Insert(RpcAddress);
|
|||
|
ServerMutex.Clear();
|
|||
|
return(Key);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::UnregisterIf (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation OPTIONAL,
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid OPTIONAL,
|
|||
|
IN unsigned int WaitForCallsToComplete
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method does the work of unregistering an interface from this
|
|||
|
rpc server. We actually do not remove the interface; what we do
|
|||
|
is to one or all of the manager entry point vector depending upon
|
|||
|
the type uuid argument supplied.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterfaceInformation - Supplies a description of the interface
|
|||
|
for which we want to unregister one or all manager entry point
|
|||
|
vectors.
|
|||
|
|
|||
|
ManagerTypeUuid - Optionally supplies the type uuid of the manager
|
|||
|
entry point vector to be removed. If this argument is not supplied,
|
|||
|
then all manager entry point vectors for this interface will
|
|||
|
be removed.
|
|||
|
|
|||
|
WaitForCallsToComplete - Supplies a flag indicating whether or not
|
|||
|
this routine should wait for all calls to complete using the
|
|||
|
interface and manager being unregistered. A non-zero value
|
|||
|
indicates to wait.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The manager entry point vector(s) are(were) successfully
|
|||
|
removed from the specified interface.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
|
|||
|
with the interface.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - The specified interface is not registered with
|
|||
|
the rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
RPC_STATUS Status;
|
|||
|
int i;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
UNUSED(WaitForCallsToComplete);
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(RpcInterfaceInformation))
|
|||
|
{
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterface = FindInterface(RpcInterfaceInformation);
|
|||
|
ServerMutex.Clear();
|
|||
|
if (RpcInterface == 0)
|
|||
|
return(RPC_S_UNKNOWN_IF);
|
|||
|
|
|||
|
if (RpcInterface->IsAutoListenInterface())
|
|||
|
{
|
|||
|
GlobalRpcServer->DecrementAutoListenInterfaceCount() ;
|
|||
|
|
|||
|
while ( RpcInterface->InqAutoListenCallCount() )
|
|||
|
{
|
|||
|
RPC_ADDRESS * Address;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while (0 != (Address = RpcAddressDictionary.Next(cursor)))
|
|||
|
{
|
|||
|
Address->EncourageCallCleanup(RpcInterface);
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
PauseExecution(500);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(RpcInterface->UnregisterManagerEpv(ManagerTypeUuid,
|
|||
|
WaitForCallsToComplete));
|
|||
|
}
|
|||
|
|
|||
|
Status = RPC_S_UNKNOWN_MGR_TYPE;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
// auto-listen intefaces have to be individually unregistered
|
|||
|
if (RpcInterface->IsAutoListenInterface())
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = RpcInterface->UnregisterManagerEpv(ManagerTypeUuid,
|
|||
|
WaitForCallsToComplete);
|
|||
|
if (RpcStatus == RPC_S_OK)
|
|||
|
{
|
|||
|
Status = RPC_S_OK;
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::InquireManagerEpv (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid, OPTIONAL
|
|||
|
OUT RPC_MGR_EPV PAPI * PAPI * ManagerEpv
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to obtain the manager entry point vector for
|
|||
|
an interface supported by this rpc server. A type uuid argument
|
|||
|
specifies which manager entry point vector is to be obtained.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterfaceInformation - Supplies a description of the interface.
|
|||
|
|
|||
|
ManagerTypeUuid - Optionally supplies the type uuid of the manager
|
|||
|
entry point vector we want returned. If no manager type uuid
|
|||
|
is specified, then the null uuid is assumed.
|
|||
|
|
|||
|
ManagerEpv - Returns the manager entry point vector.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The manager entry point vector has successfully been
|
|||
|
returned.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_MGR_TYPE - The specified type uuid is not registered
|
|||
|
with the interface.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_IF - The specified interface is not registered with
|
|||
|
the rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterface = FindInterface(RpcInterfaceInformation);
|
|||
|
ServerMutex.Clear();
|
|||
|
if (RpcInterface == 0)
|
|||
|
return(RPC_S_UNKNOWN_IF);
|
|||
|
|
|||
|
return(RpcInterface->InquireManagerEpv(ManagerTypeUuid, ManagerEpv));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::InquireBindings (
|
|||
|
OUT RPC_BINDING_VECTOR PAPI * PAPI * BindingVector
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
For each rpc protocol sequence registered with this rpc server
|
|||
|
we want to create a binding handle which can be used to make
|
|||
|
remote procedure calls using the registered rpc protocol sequence.
|
|||
|
We return a vector of these binding handles.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindingVector - Returns the vector of binding handles.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - At least one rpc protocol sequence has been registered
|
|||
|
with this rpc server, and the operation completed successfully.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete
|
|||
|
the operation.
|
|||
|
|
|||
|
RPC_S_NO_BINDINGS - No rpc protocol sequences have been successfully
|
|||
|
registered with this rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_BINDING_VECTOR PAPI * RpcBindingVector;
|
|||
|
unsigned int Index, RpcAddressIndex;
|
|||
|
RPC_ADDRESS * RpcAddress;
|
|||
|
BINDING_HANDLE * BindingHandle;
|
|||
|
int i ;
|
|||
|
RPC_CHAR PAPI * LocalNetworkAddress;
|
|||
|
int count = 0 ;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
if (RpcAddressDictionary.Size() == 0
|
|||
|
&& RpcDormantAddresses.IsQueueEmpty())
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_NO_BINDINGS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ((RpcAddress = RpcAddressDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
count += RpcAddress->InqNumNetworkAddress();
|
|||
|
}
|
|||
|
|
|||
|
RpcBindingVector = (RPC_BINDING_VECTOR PAPI *) RpcpFarAllocate(
|
|||
|
sizeof(RPC_BINDING_VECTOR) + (count -1 )
|
|||
|
* sizeof(RPC_BINDING_HANDLE) );
|
|||
|
if (RpcBindingVector == 0)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
RpcBindingVector->Count = count;
|
|||
|
for (Index = 0; Index < RpcBindingVector->Count; Index++)
|
|||
|
RpcBindingVector->BindingH[Index] = 0;
|
|||
|
|
|||
|
Index = 0;
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ((RpcAddress = RpcAddressDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
RpcAddressIndex = 0;
|
|||
|
LocalNetworkAddress = RpcAddress->
|
|||
|
GetListNetworkAddress(RpcAddressIndex) ;
|
|||
|
|
|||
|
while(LocalNetworkAddress != NULL)
|
|||
|
{
|
|||
|
BindingHandle = RpcAddress->
|
|||
|
InquireBinding(LocalNetworkAddress);
|
|||
|
if (BindingHandle == 0)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
RpcBindingVectorFree(&RpcBindingVector);
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
RpcBindingVector->BindingH[Index] = BindingHandle;
|
|||
|
Index += 1;
|
|||
|
RpcAddressIndex += 1;
|
|||
|
LocalNetworkAddress = RpcAddress->
|
|||
|
GetListNetworkAddress(RpcAddressIndex) ;
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
ASSERT(Index == RpcBindingVector->Count);
|
|||
|
|
|||
|
*BindingVector = RpcBindingVector;
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::RegisterAuthInfoHelper (
|
|||
|
IN RPC_CHAR PAPI * ServerPrincipalName,
|
|||
|
IN unsigned long AuthenticationService,
|
|||
|
IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFunction, OPTIONAL
|
|||
|
IN void PAPI * Argument OPTIONAL
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_AUTHENTICATION * Service;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
RPC_CHAR __RPC_FAR * PrincipalName;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
if (ServerPrincipalName == NULL)
|
|||
|
{
|
|||
|
ServerPrincipalName = new RPC_CHAR[1];
|
|||
|
if (ServerPrincipalName == NULL)
|
|||
|
{
|
|||
|
return (RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
ServerPrincipalName[0] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
if ( AuthenticationService == 0 )
|
|||
|
{
|
|||
|
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
|
|||
|
}
|
|||
|
|
|||
|
if (AuthenticationService == RPC_C_AUTHN_DEFAULT)
|
|||
|
{
|
|||
|
RpcpGetDefaultSecurityProviderInfo();
|
|||
|
AuthenticationService = DefaultProviderId;
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
AuthenticationDictionary.Reset(cursor);
|
|||
|
while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
if ( Service->AuthenticationService == AuthenticationService &&
|
|||
|
0 == RpcpStringCompare(Service->ServerPrincipalName, ServerPrincipalName))
|
|||
|
{
|
|||
|
Service->GetKeyFunction = GetKeyFunction;
|
|||
|
Service->Argument = Argument;
|
|||
|
ServerMutex.Clear();
|
|||
|
// Flush the server-credentials cache
|
|||
|
RpcStatus = RemoveCredentialsFromCache(AuthenticationService);
|
|||
|
return (RpcStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = IsAuthenticationServiceSupported(AuthenticationService);
|
|||
|
if ( RpcStatus != RPC_S_OK )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
if ( (RpcStatus == RPC_S_UNKNOWN_AUTHN_SERVICE) ||
|
|||
|
(RpcStatus == RPC_S_UNKNOWN_AUTHN_LEVEL) )
|
|||
|
{
|
|||
|
return (RPC_S_UNKNOWN_AUTHN_SERVICE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return (RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Service = new RPC_AUTHENTICATION;
|
|||
|
if ( Service == 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
Service->AuthenticationService = AuthenticationService;
|
|||
|
Service->ServerPrincipalName = DuplicateString(ServerPrincipalName);
|
|||
|
Service->GetKeyFunction = GetKeyFunction;
|
|||
|
Service->Argument = Argument;
|
|||
|
if ( Service->ServerPrincipalName == 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
delete Service;
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
if ( AuthenticationDictionary.Insert(Service) == -1 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
delete Service;
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::AutoRegisterAuthSvc(
|
|||
|
IN RPC_CHAR * ServerPrincipalName,
|
|||
|
IN unsigned long AuthenticationService
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
DictionaryCursor cursor;
|
|||
|
RPC_AUTHENTICATION * Service;
|
|||
|
|
|||
|
//
|
|||
|
// Don't need to auto-register the provider if it is already registered
|
|||
|
//
|
|||
|
ServerMutex.Request();
|
|||
|
AuthenticationDictionary.Reset(cursor);
|
|||
|
while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
if ( Service->AuthenticationService == AuthenticationService)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return (RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
Status = RegisterAuthInfoHelper(ServerPrincipalName,
|
|||
|
AuthenticationService,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
if (Status == RPC_S_UNKNOWN_AUTHN_SERVICE)
|
|||
|
{
|
|||
|
//
|
|||
|
// Ok to not register provider if it is disabled
|
|||
|
//
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::RegisterAuthInformation (
|
|||
|
IN RPC_CHAR PAPI * ServerPrincipalName,
|
|||
|
IN unsigned long AuthenticationService,
|
|||
|
IN RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFunction, OPTIONAL
|
|||
|
IN void PAPI * Argument OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to register authentication, authorization, and
|
|||
|
a server principal name to be used for security for this server. We
|
|||
|
will use this information to authenticate remote procedure calls.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServerPrincipalName - Supplies the principal name for the server.
|
|||
|
|
|||
|
AuthenticationService - Supplies an authentication service to use when
|
|||
|
the server receives a remote procedure call.
|
|||
|
|
|||
|
GetKeyFunction - Optionally supplies a routine to be used when the runtime
|
|||
|
needs an encryption key.
|
|||
|
|
|||
|
Argument - Optionally supplies an argument to be passed to the routine used
|
|||
|
to get keys each time it is called.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The authentication service and server principal name have
|
|||
|
been registered with this RPC server.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
|
|||
|
not supported.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
RPC_CHAR *PrincName;
|
|||
|
|
|||
|
Status = RegisterAuthInfoHelper(ServerPrincipalName,
|
|||
|
AuthenticationService,
|
|||
|
GetKeyFunction,
|
|||
|
Argument);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (AuthenticationService != RPC_C_AUTHN_GSS_NEGOTIATE)
|
|||
|
{
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
Status = AutoRegisterAuthSvc(ServerPrincipalName, RPC_C_AUTHN_WINNT);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
Status = AutoRegisterAuthSvc(ServerPrincipalName, RPC_C_AUTHN_GSS_KERBEROS);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::AcquireCredentials (
|
|||
|
IN unsigned long AuthenticationService,
|
|||
|
IN unsigned long AuthenticationLevel,
|
|||
|
OUT SECURITY_CREDENTIALS ** SecurityCredentials
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The protocol modules will use this to obtain a set of credentials
|
|||
|
for the specified authentication service, assuming that the server
|
|||
|
supports them.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AuthenticationService - Supplies the authentication service for which
|
|||
|
we hope to obtain credentials.
|
|||
|
|
|||
|
AuthenticationLevel - Supplies the authentication level to be used.
|
|||
|
|
|||
|
SecurityCredentials - Returns the security credentials.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - You have been given some security credentials, which you need
|
|||
|
to free using RPC_SERVER::FreeCredentials when you are done with
|
|||
|
them.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
|
|||
|
not supported by the current configuration.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_AUTHENTICATION * Service;
|
|||
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
AuthenticationDictionary.Reset(cursor);
|
|||
|
while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
if ( Service->AuthenticationService == AuthenticationService )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
RpcStatus = FindServerCredentials(
|
|||
|
Service->GetKeyFunction,
|
|||
|
Service->Argument,
|
|||
|
AuthenticationService,
|
|||
|
AuthenticationLevel,
|
|||
|
Service->ServerPrincipalName,
|
|||
|
SecurityCredentials
|
|||
|
);
|
|||
|
|
|||
|
VALIDATE(RpcStatus)
|
|||
|
{
|
|||
|
RPC_S_OK,
|
|||
|
RPC_S_SEC_PKG_ERROR,
|
|||
|
RPC_S_OUT_OF_MEMORY,
|
|||
|
RPC_S_INVALID_AUTH_IDENTITY,
|
|||
|
ERROR_SHUTDOWN_IN_PROGRESS,
|
|||
|
RPC_S_UNKNOWN_AUTHN_SERVICE
|
|||
|
} END_VALIDATE;
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RPC_SERVER::FreeCredentials (
|
|||
|
IN SECURITY_CREDENTIALS * SecurityCredentials
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
A protocol module will indicate that it is through using a set of
|
|||
|
security credentials, obtained from RPC_SERVER::AcquireCredentials,
|
|||
|
using this routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SecurityCredentials - Supplies the security credentials to be freed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
SecurityCredentials->FreeCredentials();
|
|||
|
delete SecurityCredentials;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::RegisterInterface (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN RPC_UUID PAPI * ManagerTypeUuid,
|
|||
|
IN RPC_MGR_EPV PAPI * ManagerEpv,
|
|||
|
IN unsigned int Flags,
|
|||
|
IN unsigned int MaxCalls,
|
|||
|
IN unsigned int MaxRpcSize,
|
|||
|
IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used by server application to register a manager
|
|||
|
entry point vector and optionally an interface. If the interface
|
|||
|
has not been registered, then it will be registered. If it has
|
|||
|
already been registered, the manager entry point vector will be
|
|||
|
added to it under the specified type uuid.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RpcInterfaceInformation - Supplies a description of the interface to
|
|||
|
be registered. We will make a copy of this information.
|
|||
|
|
|||
|
ManagerTypeUuid - Optionally supplies the type uuid for the specified
|
|||
|
manager entry point vector. If no type uuid is supplied, then
|
|||
|
the null uuid will be used as the type uuid.
|
|||
|
|
|||
|
ManagerEpv - Optionally supplies a manager entry point vector corresponding
|
|||
|
to the type uuid. If a manager entry point vector is not supplied,
|
|||
|
then the manager entry point vector in the interface will be
|
|||
|
used.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The specified rpc interface has been successfully
|
|||
|
registered with the rpc server. It is now ready to accept
|
|||
|
remote procedure calls.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to register
|
|||
|
the rpc interface with the rpc server.
|
|||
|
|
|||
|
RPC_S_TYPE_ALREADY_REGISTERED - A manager entry point vector has
|
|||
|
already been registered for the supplied rpc interface and
|
|||
|
manager type UUID.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
RPC_ADDRESS *RpcAddress ;
|
|||
|
DictionaryCursor cursor;
|
|||
|
BOOL fInterfaceFound;
|
|||
|
|
|||
|
if ( ManagerEpv == 0 )
|
|||
|
{
|
|||
|
|
|||
|
ManagerEpv = RpcInterfaceInformation->DefaultManagerEpv;
|
|||
|
|
|||
|
if ( (PtrToUlong(ManagerEpv)) == 0xFFFFFFFF)
|
|||
|
{
|
|||
|
// Stub compiled with -no_default_epv.
|
|||
|
return (RPC_S_INVALID_ARG);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterface = FindOrCreateInterfaceInternal(RpcInterfaceInformation, Flags, MaxCalls,
|
|||
|
MaxRpcSize, IfCallbackFn, &RpcStatus, &fInterfaceFound);
|
|||
|
if (RpcInterface == NULL)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
|
|||
|
if (fInterfaceFound)
|
|||
|
{
|
|||
|
// if it was found, update the information
|
|||
|
RpcStatus = RpcInterface->UpdateRpcInterfaceInformation(RpcInterfaceInformation,
|
|||
|
Flags, MaxCalls, MaxRpcSize, IfCallbackFn);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = RpcInterface->RegisterTypeManager(ManagerTypeUuid, ManagerEpv);
|
|||
|
|
|||
|
if (Flags & RPC_IF_AUTOLISTEN)
|
|||
|
{
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ( (RpcAddress = RpcAddressDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
RpcStatus = RpcAddress->ServerStartingToListen(
|
|||
|
this->MinimumCallThreads,
|
|||
|
MaxCalls);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_SERVER::CreateOrUpdateAddresses (void)
|
|||
|
/*++
|
|||
|
Function Name: CreateOrUpdateAddresses
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
The runtime just received a notification that a new protocol was loaded. We need
|
|||
|
to create an ADDRESS object, listen on it and update the RPCSS bindings
|
|||
|
appropriately.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
RPC_BINDING_VECTOR *BindingVector = 0;
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
BOOL fChanged = 0;
|
|||
|
RPC_ADDRESS *Address;
|
|||
|
QUEUE tempQueue;
|
|||
|
BOOL fTempQueueHasContents = FALSE;
|
|||
|
int i;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
unsigned int Length;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
Address = (RPC_ADDRESS *) RpcDormantAddresses.TakeOffQueue(&Length);
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
if (Address == 0)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(Length == 0);
|
|||
|
|
|||
|
if (Address->RestartAddress(MinimumCallThreads,
|
|||
|
MaximumConcurrentCalls) != RPC_S_OK)
|
|||
|
{
|
|||
|
fTempQueueHasContents = TRUE;
|
|||
|
if (tempQueue.PutOnQueue(Address, 0) != 0)
|
|||
|
{
|
|||
|
// putting on the temporary queue failed - out of memory
|
|||
|
// in this case we'd rather cut the PnP process for now, and we'll
|
|||
|
// go with what we have
|
|||
|
// return the address
|
|||
|
ServerMutex.Request();
|
|||
|
// guaranteed to succeed
|
|||
|
RpcDormantAddresses.PutOnQueue(Address, 0);
|
|||
|
ServerMutex.Clear();
|
|||
|
// break into merging the temp queue with the permanent one
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fChanged = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (fTempQueueHasContents)
|
|||
|
{
|
|||
|
ServerMutex.Request();
|
|||
|
// merge back the queues - this should succeed if we have only added protocols. If we have
|
|||
|
// removed protocols, this will fail, and we'll have a bug. Nothing we can do about it here.
|
|||
|
RpcDormantAddresses.MergeWithQueue(&tempQueue);
|
|||
|
ServerMutex.Clear();
|
|||
|
}
|
|||
|
|
|||
|
if (fChanged)
|
|||
|
{
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
|
|||
|
//
|
|||
|
// Inquire the new bindings, and update them in the endpoint mapper
|
|||
|
//
|
|||
|
Status = InquireBindings(&BindingVector);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
|
|||
|
while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
if (RpcInterface->NeedToUpdateBindings())
|
|||
|
{
|
|||
|
// we know an interface never gets deleted, only marked as
|
|||
|
// unregistered. Therefore, it is safe to release the mutex
|
|||
|
// and do the slow UpdateBindings outside the mutex
|
|||
|
ServerMutex.Clear();
|
|||
|
if ((Status = RpcInterface->UpdateBindings(BindingVector))
|
|||
|
!= RPC_S_OK)
|
|||
|
{
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
ServerMutex.Request();
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
Status = RpcBindingVectorFree(&BindingVector);
|
|||
|
ASSERT(Status == RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if (BindingVector)
|
|||
|
{
|
|||
|
Status = RpcBindingVectorFree(&BindingVector);
|
|||
|
ASSERT(Status == RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RPC_INTERFACE *
|
|||
|
RPC_SERVER::FindOrCreateInterfaceInternal (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN unsigned int Flags,
|
|||
|
IN unsigned int MaxCalls,
|
|||
|
IN unsigned int MaxRpcSize,
|
|||
|
IN RPC_IF_CALLBACK_FN PAPI *IfCallbackFn,
|
|||
|
OUT RPC_STATUS *Status,
|
|||
|
OUT BOOL *fInterfaceFound
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: FindOrCreateInterfaceInternal
|
|||
|
|
|||
|
Parameters:
|
|||
|
RpcInterfaceInformation
|
|||
|
Flags
|
|||
|
MaxCalls
|
|||
|
MaxRpcSize
|
|||
|
IfCallbackFn
|
|||
|
Status - meaningless if the return value is not NULL.
|
|||
|
fInterfaceFound - TRUE if the interface was found, FALSE if it was created
|
|||
|
|
|||
|
Description:
|
|||
|
Find or creates an interface with the appropriate parameters
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
|
|||
|
ServerMutex.VerifyOwned();
|
|||
|
|
|||
|
RpcInterface = FindInterface(RpcInterfaceInformation);
|
|||
|
if ( RpcInterface == 0 )
|
|||
|
{
|
|||
|
RpcInterface = new RPC_INTERFACE(RpcInterfaceInformation,
|
|||
|
this, Flags, MaxCalls, MaxRpcSize, IfCallbackFn, Status);
|
|||
|
if ( RpcInterface == 0 )
|
|||
|
{
|
|||
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
if ( AddInterface(RpcInterface) != 0 )
|
|||
|
{
|
|||
|
delete RpcInterface;
|
|||
|
*Status = RPC_S_OUT_OF_MEMORY;
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
if (Flags & RPC_IF_AUTOLISTEN)
|
|||
|
{
|
|||
|
GlobalRpcServer->IncrementAutoListenInterfaceCount() ;
|
|||
|
}
|
|||
|
*fInterfaceFound = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*fInterfaceFound = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
*Status = RPC_S_OK;
|
|||
|
return RpcInterface;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_INTERFACE *
|
|||
|
RPC_SERVER::FindOrCreateInterface (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
OUT RPC_STATUS *Status
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
BOOL fIgnored;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
RpcInterface = FindOrCreateInterfaceInternal(RpcInterfaceInformation,
|
|||
|
RPC_IF_ALLOW_SECURE_ONLY, 0, gMaxRpcSize, NULL, Status, &fIgnored);
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
return RpcInterface;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::InterfaceExported (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN UUID_VECTOR *MyObjectUuidVector,
|
|||
|
IN unsigned char *MyAnnotation,
|
|||
|
IN BOOL MyfReplace
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name:InterfaceExported
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
RpcEpRegister was called on this interface. We need to keep track
|
|||
|
of the parameters, so that if we get a PNP notification, we can update
|
|||
|
the bindings using there params
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
RpcInterface = FindOrCreateInterface (RpcInterfaceInformation, &Status);
|
|||
|
if (RpcInterface == NULL)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
return RpcInterface->InterfaceExported(
|
|||
|
MyObjectUuidVector,
|
|||
|
MyAnnotation,
|
|||
|
MyfReplace);
|
|||
|
}
|
|||
|
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::NsInterfaceExported (
|
|||
|
IN unsigned long EntryNameSyntax,
|
|||
|
IN RPC_CHAR *EntryName,
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN BOOL fUnexport
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
RPC_STATUS Status;
|
|||
|
HMODULE hLocator;
|
|||
|
|
|||
|
if (pNsBindingExport == 0)
|
|||
|
{
|
|||
|
hLocator = LoadLibrary ((const RPC_SCHAR *)RPC_CONST_STRING("rpcns4.dll"));
|
|||
|
if (hLocator == 0)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
pNsBindingExport = (NS_EXPORT_FUNC) GetProcAddress(hLocator,
|
|||
|
"RpcNsBindingExportW");
|
|||
|
if (pNsBindingExport == 0)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
pNsBindingUnexport = (NS_UNEXPORT_FUNC) GetProcAddress(hLocator,
|
|||
|
"RpcNsBindingUnexportW");
|
|||
|
if (pNsBindingUnexport == 0)
|
|||
|
{
|
|||
|
pNsBindingExport = 0;
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RpcInterface = FindOrCreateInterface (RpcInterfaceInformation, &Status);
|
|||
|
if (RpcInterface == NULL)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (fUnexport == 0)
|
|||
|
{
|
|||
|
return RpcInterface->NsInterfaceExported(
|
|||
|
EntryNameSyntax,
|
|||
|
EntryName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return RpcInterface->NsInterfaceUnexported(
|
|||
|
EntryNameSyntax,
|
|||
|
EntryName);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::EnumerateAndCallEachAddress (
|
|||
|
IN AddressCallbackType actType,
|
|||
|
IN OUT void *Context OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: DestroyContextHandlesForInterface
|
|||
|
|
|||
|
Parameters:
|
|||
|
actType - the type of callback.
|
|||
|
Context - opaque memory block to be passed to the callback.
|
|||
|
|
|||
|
Description:
|
|||
|
This function is called when we want to invoke a specific method
|
|||
|
on each address.
|
|||
|
|
|||
|
Returns:
|
|||
|
RPC_S_OK for success or RPC_S_* for error
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_ADDRESS_DICT AddressDict;
|
|||
|
RPC_ADDRESS_DICT *AddressDictToUse;
|
|||
|
RPC_ADDRESS *CurrentAddress;
|
|||
|
BOOL UsingAddressDictionaryCopy;
|
|||
|
int Result;
|
|||
|
DictionaryCursor cursor;
|
|||
|
DestroyContextHandleCallbackContext *ContextHandleContext;
|
|||
|
|
|||
|
// try to copy all entries in the address dictionary to the local
|
|||
|
// dictionary. We will walk the address list from there to avoid
|
|||
|
// holding the server mutex while walking potentially large tree.
|
|||
|
// If we do that, only the page faults will be enough to kill the
|
|||
|
// server. On the other hand, we can't rely that the memory will be
|
|||
|
// there. Therefore, we attempt to copy the dictionary under the
|
|||
|
// mutex, but if this fails, we will retain the mutex and go ahead
|
|||
|
// with the cleanup. The logic behind this is that if we don't have
|
|||
|
// the few bytes to copy the dictionary, probably the server isn't
|
|||
|
// doing anything, and holding the mutex won't hurt it anymore
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (actType == actDestroyContextHandle)
|
|||
|
{
|
|||
|
RPC_INTERFACE *Interface;
|
|||
|
|
|||
|
ContextHandleContext = (DestroyContextHandleCallbackContext *)Context;
|
|||
|
Interface = FindInterface(ContextHandleContext->RpcInterfaceInformation);
|
|||
|
ASSERT(Interface);
|
|||
|
// the interface must use strict context handles
|
|||
|
ASSERT(Interface->DoesInterfaceUseNonStrict() == FALSE);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
UsingAddressDictionaryCopy = AddressDict.ExpandToSize(RpcAddressDictionary.Size());
|
|||
|
|
|||
|
if (UsingAddressDictionaryCopy)
|
|||
|
{
|
|||
|
AddressDictToUse = &AddressDict;
|
|||
|
|
|||
|
RpcAddressDictionary.Reset(cursor);
|
|||
|
while ( (CurrentAddress = RpcAddressDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
// we never destroy addresses. Therefore, we don't need to mark
|
|||
|
// those addresses as used in any way
|
|||
|
Result = AddressDict.Insert(CurrentAddress);
|
|||
|
// this must succeed as we have reserved enough size
|
|||
|
ASSERT(Result != -1);
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Clear();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AddressDictToUse = &RpcAddressDictionary;
|
|||
|
}
|
|||
|
|
|||
|
// N.B. We may, or may not have the ServerMutex here - depending on how
|
|||
|
// we were doing with memory
|
|||
|
AddressDictToUse->Reset(cursor);
|
|||
|
while ( (CurrentAddress = AddressDictToUse->Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
switch (actType)
|
|||
|
{
|
|||
|
case actDestroyContextHandle:
|
|||
|
ContextHandleContext = (DestroyContextHandleCallbackContext *)Context;
|
|||
|
CurrentAddress->DestroyContextHandlesForInterface(
|
|||
|
ContextHandleContext->RpcInterfaceInformation,
|
|||
|
ContextHandleContext->RundownContextHandles
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case actCleanupIdleSContext:
|
|||
|
CurrentAddress->CleanupIdleSContexts();
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ASSERT(0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!UsingAddressDictionaryCopy)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ENTRY
|
|||
|
I_RpcNsInterfaceExported (
|
|||
|
IN unsigned long EntryNameSyntax,
|
|||
|
IN unsigned short *EntryName,
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
|
|||
|
)
|
|||
|
{
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
InitializeIfNecessary();
|
|||
|
|
|||
|
return (GlobalRpcServer->NsInterfaceExported(
|
|||
|
EntryNameSyntax,
|
|||
|
EntryName,
|
|||
|
RpcInterfaceInformation, 0));
|
|||
|
#else
|
|||
|
return RPC_S_CANNOT_SUPPORT;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ENTRY
|
|||
|
I_RpcNsInterfaceUnexported (
|
|||
|
IN unsigned long EntryNameSyntax,
|
|||
|
IN unsigned short *EntryName,
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation
|
|||
|
)
|
|||
|
{
|
|||
|
#if !defined(NO_LOCATOR_CODE)
|
|||
|
InitializeIfNecessary();
|
|||
|
|
|||
|
return (GlobalRpcServer->NsInterfaceExported(
|
|||
|
EntryNameSyntax,
|
|||
|
EntryName,
|
|||
|
RpcInterfaceInformation, 1));
|
|||
|
#else
|
|||
|
return RPC_S_CANNOT_SUPPORT;
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#define MAXIMUM_CACHED_THREAD_TIMEOUT (1000L * 60L * 60L)
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
BaseCachedThreadRoutine (
|
|||
|
IN CACHED_THREAD * CachedThread
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Each thread will execute this routine. When it first gets called, it
|
|||
|
will immediately call the procedure and parameter specified in the
|
|||
|
cached thread object. After that it will wait on its event and then
|
|||
|
execute the specified routine everytime it gets woken up. If the wait
|
|||
|
on the event times out, the thread will exit unless it has been protected.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CachedThread - Supplies the cached thread object to be used by this
|
|||
|
thread.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_SERVER * RpcServer = CachedThread->OwningRpcServer;
|
|||
|
THREAD *pThread = RpcpGetThreadPointer();
|
|||
|
long WaitTimeout;
|
|||
|
|
|||
|
ASSERT(pThread);
|
|||
|
|
|||
|
while (pThread->ThreadHandle() == (void *) -1)
|
|||
|
{
|
|||
|
Sleep(1);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(pThread->ThreadHandle());
|
|||
|
|
|||
|
CachedThread->SetThread(pThread);
|
|||
|
|
|||
|
if (pThread->DebugCell)
|
|||
|
{
|
|||
|
pThread->DebugCell->TID = (unsigned short)GetCurrentThreadId();
|
|||
|
pThread->DebugCell->LastUpdateTime = NtGetTickCount();
|
|||
|
}
|
|||
|
|
|||
|
for(;;)
|
|||
|
{
|
|||
|
if (CachedThread->CallProcedure())
|
|||
|
{
|
|||
|
#ifdef RPC_OLD_IO_PROTECTION
|
|||
|
// This thread has already timed-out waiting on
|
|||
|
// a transport level cache. Let it go now...
|
|||
|
ASSERT(pThread->InqProtectCount() == 1);
|
|||
|
#endif
|
|||
|
|
|||
|
if (pThread->IsIOPending() == FALSE)
|
|||
|
{
|
|||
|
delete CachedThread;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// we're a cached IOCP thread - we need to unjoin the IOCP
|
|||
|
UnjoinCompletionPort();
|
|||
|
}
|
|||
|
|
|||
|
WaitTimeout = gThreadTimeout;
|
|||
|
|
|||
|
// Now we cache this thread. This consists of clearing the
|
|||
|
// work available flag and inserting the thread cache object into
|
|||
|
// the list thread cache objects.
|
|||
|
|
|||
|
CachedThread->WorkAvailableFlag = WorkIsNotAvailable;
|
|||
|
|
|||
|
RpcServer->ThreadCacheMutex.Request();
|
|||
|
RpcServer->InsertIntoFreeList(CachedThread);
|
|||
|
RpcServer->ThreadCacheMutex.Clear();
|
|||
|
|
|||
|
// Now we loop waiting for work. We get out of the loop in three
|
|||
|
// ways: (1) a timeout occurs and there is work to do, (2) the
|
|||
|
// event gets kicked because there is work to do, (3) a timeout
|
|||
|
// occurs, there is no work to do, and the thread is not protected.
|
|||
|
|
|||
|
for (;;)
|
|||
|
{
|
|||
|
|
|||
|
// Ignore spurious signals.
|
|||
|
while( (CachedThread->WaitForWorkEvent.Wait(WaitTimeout) == 0)
|
|||
|
&& (CachedThread->WorkAvailableFlag == WorkIsNotAvailable) )
|
|||
|
;
|
|||
|
|
|||
|
|
|||
|
if (CachedThread->WorkAvailableFlag == WorkIsAvailable)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// We must take the lock to avoid a race condition where another
|
|||
|
// thread is trying to signal us right now.
|
|||
|
|
|||
|
RpcServer->ThreadCacheMutex.Request();
|
|||
|
|
|||
|
if (CachedThread->WorkAvailableFlag)
|
|||
|
{
|
|||
|
RpcServer->ThreadCacheMutex.Clear();
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (pThread->IsIOPending())
|
|||
|
{
|
|||
|
// If we reach here, there is no work available, and the thread
|
|||
|
// is protected. We just need to wait again. There is no need to
|
|||
|
// busy wait if the thread is protected and it keeps timing out.
|
|||
|
|
|||
|
if (WaitTimeout < MAXIMUM_CACHED_THREAD_TIMEOUT/2)
|
|||
|
{
|
|||
|
WaitTimeout = WaitTimeout * 2;
|
|||
|
}
|
|||
|
|
|||
|
// Since this thread can't exit anyway, move it to the front of the
|
|||
|
// free list so it will be reused first.
|
|||
|
|
|||
|
RpcServer->RemoveFromFreeList(CachedThread);
|
|||
|
RpcServer->InsertIntoFreeList(CachedThread);
|
|||
|
|
|||
|
RpcServer->ThreadCacheMutex.Clear();
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// No work available.
|
|||
|
|
|||
|
#ifdef RPC_OLD_IO_PROTECTION
|
|||
|
ASSERT(pThread->InqProtectCount() == 1);
|
|||
|
#endif
|
|||
|
|
|||
|
// There is no work available, and this thread is not
|
|||
|
// protected, so we can safely let it commit suicide.
|
|||
|
|
|||
|
RpcServer->RemoveFromFreeList(CachedThread);
|
|||
|
RpcServer->ThreadCacheMutex.Clear();
|
|||
|
|
|||
|
delete CachedThread;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(CachedThread->WorkAvailableFlag == WorkIsAvailable);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NO_RETURN;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::CreateThread (
|
|||
|
IN THREAD_PROC Procedure,
|
|||
|
IN void * Parameter
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to create a new thread which will begin
|
|||
|
executing the specified procedure. The procedure will be passed
|
|||
|
parameter as the argument.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Procedure - Supplies the procedure which the new thread should
|
|||
|
begin executing.
|
|||
|
|
|||
|
Parameter - Supplies the argument to be passed to the procedure.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - We successfully created a new thread and started it
|
|||
|
executing the supplied procedure.
|
|||
|
|
|||
|
RPC_S_OUT_OF_THREADS - We could not create another thread.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
|||
|
the data structures we need to complete this operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
THREAD * Thread;
|
|||
|
CACHED_THREAD * CachedThread;
|
|||
|
RPC_STATUS RpcStatus = RPC_S_OK;
|
|||
|
|
|||
|
ThreadCacheMutex.Request();
|
|||
|
|
|||
|
CachedThread = RemoveHeadFromFreeList();
|
|||
|
if (CachedThread)
|
|||
|
{
|
|||
|
// set all parameters within the mutex to avoid races
|
|||
|
CachedThread->SetWakeUpThreadParams(Procedure, Parameter);
|
|||
|
|
|||
|
ThreadCacheMutex.Clear();
|
|||
|
|
|||
|
CachedThread->WakeUpThread();
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
ThreadCacheMutex.Clear();
|
|||
|
|
|||
|
if (IsServerSideDebugInfoEnabled())
|
|||
|
{
|
|||
|
RpcStatus = InitializeServerSideCellHeapIfNecessary();
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
|
|||
|
CachedThread = new CACHED_THREAD(Procedure, Parameter, this, &RpcStatus);
|
|||
|
if ( CachedThread == 0 )
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
if ( RpcStatus != RPC_S_OK )
|
|||
|
{
|
|||
|
delete CachedThread;
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( RpcStatus == RPC_S_OK );
|
|||
|
|
|||
|
Thread = new THREAD((THREAD_PROC) BaseCachedThreadRoutine, CachedThread,
|
|||
|
&RpcStatus);
|
|||
|
|
|||
|
if (Thread == 0)
|
|||
|
{
|
|||
|
delete CachedThread;
|
|||
|
return(RPC_S_OUT_OF_THREADS);
|
|||
|
}
|
|||
|
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
{
|
|||
|
delete CachedThread;
|
|||
|
delete Thread;
|
|||
|
if (RpcStatus == ERROR_MAX_THRDS_REACHED)
|
|||
|
RpcStatus = RPC_S_OUT_OF_THREADS;
|
|||
|
}
|
|||
|
|
|||
|
return(RpcStatus);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::InquireInterfaceIds (
|
|||
|
OUT RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR * InterfaceIdVector
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to obtain a vector of the interface identifiers of
|
|||
|
the interfaces supported by this server.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IfIdVector - Returns a vector of the interfaces supported by this server.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - Everything worked out just great.
|
|||
|
|
|||
|
RPC_S_NO_INTERFACES - No interfaces have been registered with the runtime.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate
|
|||
|
the interface id vector.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
if (RpcInterfaceDictionary.Size() == 0)
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
*InterfaceIdVector = 0;
|
|||
|
return RPC_S_NO_INTERFACES;
|
|||
|
}
|
|||
|
|
|||
|
*InterfaceIdVector = (RPC_IF_ID_VECTOR __RPC_FAR *) RpcpFarAllocate(
|
|||
|
sizeof(RPC_IF_ID_VECTOR) + (RpcInterfaceDictionary.Size() - 1)
|
|||
|
* sizeof(RPC_IF_ID __RPC_FAR *));
|
|||
|
if ( *InterfaceIdVector == 0 )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
(*InterfaceIdVector)->Count = 0;
|
|||
|
(*InterfaceIdVector)->IfId[0] = (RPC_IF_ID __RPC_FAR *) RpcpFarAllocate(
|
|||
|
sizeof(RPC_IF_ID));
|
|||
|
RpcInterfaceDictionary.Reset(cursor);
|
|||
|
|
|||
|
RPC_INTERFACE * RpcInterface;
|
|||
|
while ((RpcInterface = RpcInterfaceDictionary.Next(cursor)) != 0)
|
|||
|
{
|
|||
|
(*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count] =
|
|||
|
RpcInterface->InquireInterfaceId();
|
|||
|
if ( (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count] != 0 )
|
|||
|
{
|
|||
|
RPC_IF_ID * Interface = (*InterfaceIdVector)->IfId[(*InterfaceIdVector)->Count];
|
|||
|
(*InterfaceIdVector)->Count += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
ServerMutex.Clear();
|
|||
|
|
|||
|
if (0 == (*InterfaceIdVector)->Count)
|
|||
|
{
|
|||
|
RpcpFarFree(*InterfaceIdVector);
|
|||
|
*InterfaceIdVector = 0;
|
|||
|
return RPC_S_NO_INTERFACES;
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::InquirePrincipalName (
|
|||
|
IN unsigned long AuthenticationService,
|
|||
|
OUT RPC_CHAR __RPC_FAR * __RPC_FAR * ServerPrincipalName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The operation completed successfully.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the
|
|||
|
operation.
|
|||
|
|
|||
|
RPC_S_UNKNOWN_AUTHN_SERVICE - The specified authentication service is
|
|||
|
not supported.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_AUTHENTICATION * Service;
|
|||
|
DictionaryCursor cursor;
|
|||
|
|
|||
|
ServerMutex.Request();
|
|||
|
AuthenticationDictionary.Reset(cursor);
|
|||
|
while ( (Service = AuthenticationDictionary.Next(cursor)) != 0 )
|
|||
|
{
|
|||
|
if ( Service->AuthenticationService == AuthenticationService )
|
|||
|
{
|
|||
|
ServerMutex.Clear();
|
|||
|
*ServerPrincipalName = DuplicateString(
|
|||
|
Service->ServerPrincipalName);
|
|||
|
if ( *ServerPrincipalName == 0 )
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ServerMutex.Clear();
|
|||
|
return(RPC_S_UNKNOWN_AUTHN_SERVICE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RPC_SERVER::RegisterRpcForwardFunction (
|
|||
|
RPC_FORWARD_FUNCTION * pForwardFunction
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Sets the RPC_SERVER pEpmapperForwardFunction. (The pEpmapperForwardFunction
|
|||
|
is the function the runtime can call when it receives a pkt for a
|
|||
|
dynamic endpoint. pEpmapperForwardFunction will return endpoint of
|
|||
|
the server to forward the pkt to).
|
|||
|
|
|||
|
Arguments:
|
|||
|
pForwardFunction - pointer to the epmapper forward function.
|
|||
|
|
|||
|
Return Value:
|
|||
|
none
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
pRpcForwardFunction = pForwardFunction;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_SERVER::UnregisterEndpoint (
|
|||
|
IN RPC_CHAR __RPC_FAR * Protseq,
|
|||
|
IN RPC_CHAR __RPC_FAR * Endpoint
|
|||
|
)
|
|||
|
{
|
|||
|
return (RPC_S_CANNOT_SUPPORT);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_ADDRESS::RPC_ADDRESS (
|
|||
|
IN OUT RPC_STATUS PAPI * RpcStatus
|
|||
|
) : AddressMutex(RpcStatus,
|
|||
|
TRUE // pre-allocate semaphore
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We just need to initialization some stuff to zero. That way if we
|
|||
|
later have to delete this address because of an error in initialization
|
|||
|
we can tell what instance variables need to be freed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NetworkAddress = 0;
|
|||
|
Endpoint = 0;
|
|||
|
RpcProtocolSequence = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_ADDRESS::~RPC_ADDRESS (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will only get called if part way through initialization
|
|||
|
an error occurs. We just need to free up any memory used by instance
|
|||
|
variables. Once FireUpManager has been called and succeeds, the
|
|||
|
address will never be destroyed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (Endpoint != 0)
|
|||
|
delete Endpoint;
|
|||
|
if (RpcProtocolSequence != 0)
|
|||
|
delete RpcProtocolSequence;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
RPC_CHAR *
|
|||
|
RPC_ADDRESS::GetListNetworkAddress (
|
|||
|
IN unsigned int Index
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
A pointer to the network address for this address is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (Index >= pNetworkAddressVector->Count)
|
|||
|
{
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
return(pNetworkAddressVector->NetworkAddresses[Index]);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ADDRESS::CopyDescriptor (
|
|||
|
IN void *SecurityDescriptor,
|
|||
|
OUT void **OutDescriptor
|
|||
|
)
|
|||
|
{
|
|||
|
BOOL b;
|
|||
|
SECURITY_DESCRIPTOR_CONTROL Control;
|
|||
|
DWORD Revision;
|
|||
|
DWORD BufferLength;
|
|||
|
|
|||
|
if ( IsValidSecurityDescriptor(SecurityDescriptor) == FALSE )
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_SECURITY_DESC);
|
|||
|
}
|
|||
|
|
|||
|
if (FALSE == GetSecurityDescriptorControl(SecurityDescriptor, &Control, &Revision))
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_SECURITY_DESC);
|
|||
|
}
|
|||
|
|
|||
|
if (Control & SE_SELF_RELATIVE)
|
|||
|
{
|
|||
|
//
|
|||
|
// Already self-relative, just copy it.
|
|||
|
//
|
|||
|
|
|||
|
BufferLength = GetSecurityDescriptorLength(SecurityDescriptor);
|
|||
|
|
|||
|
ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR));
|
|||
|
|
|||
|
*OutDescriptor = RpcpFarAllocate(BufferLength);
|
|||
|
if (*OutDescriptor == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
memcpy(*OutDescriptor, SecurityDescriptor, BufferLength);
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make self-relative and copy it.
|
|||
|
//
|
|||
|
BufferLength = 0;
|
|||
|
b = MakeSelfRelativeSD(SecurityDescriptor, 0, &BufferLength);
|
|||
|
ASSERT(b == FALSE);
|
|||
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
|||
|
{
|
|||
|
return(RPC_S_INVALID_SECURITY_DESC);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(BufferLength >= sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
|||
|
|
|||
|
*OutDescriptor = RpcpFarAllocate(BufferLength);
|
|||
|
|
|||
|
if (*OutDescriptor == 0)
|
|||
|
{
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
b = MakeSelfRelativeSD(SecurityDescriptor,
|
|||
|
*OutDescriptor,
|
|||
|
&BufferLength);
|
|||
|
|
|||
|
if (b == FALSE)
|
|||
|
{
|
|||
|
ASSERT(GetLastError() != ERROR_INSUFFICIENT_BUFFER);
|
|||
|
delete *OutDescriptor;
|
|||
|
|
|||
|
return(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ADDRESS::SetEndpointAndStuff (
|
|||
|
IN RPC_CHAR PAPI * NetworkAddress,
|
|||
|
IN RPC_CHAR PAPI * Endpoint,
|
|||
|
IN RPC_CHAR PAPI * RpcProtocolSequence,
|
|||
|
IN RPC_SERVER * Server,
|
|||
|
IN unsigned int StaticEndpointFlag,
|
|||
|
IN unsigned int PendingQueueSize,
|
|||
|
IN void PAPI *SecurityDescriptor,
|
|||
|
IN unsigned long EndpointFlags,
|
|||
|
IN unsigned long NICFlags,
|
|||
|
IN NETWORK_ADDRESS_VECTOR *pNetworkAddressVector
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We just need to set some instance variables of this rpc address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - Supplies the endpoint for this rpc address.
|
|||
|
|
|||
|
RpcProtocolSequence - Supplies the rpc protocol sequence for this
|
|||
|
rpc address.
|
|||
|
|
|||
|
Server - Supplies the rpc server which owns this rpc address.
|
|||
|
|
|||
|
StaticEndpointFlag - Supplies a flag which specifies whether this
|
|||
|
address has a static endpoint or a dynamic endpoint.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
|
|||
|
this->NetworkAddress = NetworkAddress;
|
|||
|
this->Endpoint = Endpoint;
|
|||
|
this->RpcProtocolSequence = RpcProtocolSequence;
|
|||
|
this->pNetworkAddressVector = pNetworkAddressVector;
|
|||
|
this->Server = Server;
|
|||
|
this->StaticEndpointFlag = StaticEndpointFlag;
|
|||
|
this->PendingQueueSize = PendingQueueSize;
|
|||
|
this->EndpointFlags = EndpointFlags;
|
|||
|
this->NICFlags = NICFlags;
|
|||
|
|
|||
|
if (SecurityDescriptor)
|
|||
|
{
|
|||
|
Status = CopyDescriptor(SecurityDescriptor,
|
|||
|
&this->SecurityDescriptor);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ADDRESS::FindInterfaceTransfer (
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER InterfaceIdentifier,
|
|||
|
IN PRPC_SYNTAX_IDENTIFIER ProposedTransferSyntaxes,
|
|||
|
IN unsigned int NumberOfTransferSyntaxes,
|
|||
|
OUT PRPC_SYNTAX_IDENTIFIER AcceptedTransferSyntax,
|
|||
|
OUT RPC_INTERFACE ** RpcInterface,
|
|||
|
OUT BOOL *fIsInterfaceTransferPreferred,
|
|||
|
OUT int *ProposedTransferSyntaxIndex,
|
|||
|
OUT int *AvailableTransferSyntaxIndex
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method is used to determine if a client bind request can be
|
|||
|
accepted or not. All we have got to do here is hand off to the
|
|||
|
server which owns this address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
InterfaceIdentifier - Supplies the syntax identifier for the
|
|||
|
interface; this is the interface uuid and version.
|
|||
|
|
|||
|
ProposedTransferSyntaxes - Supplies a list of one or more transfer
|
|||
|
syntaxes which the client initiating the binding supports. The
|
|||
|
server should pick one of these which is supported by the
|
|||
|
interface.
|
|||
|
|
|||
|
NumberOfTransferSyntaxes - Supplies the number of transfer syntaxes
|
|||
|
specified in the proposed transfer syntaxes argument.
|
|||
|
|
|||
|
AcceptedTransferSyntax - Returns the transfer syntax which the
|
|||
|
server accepted.
|
|||
|
|
|||
|
RpcInterface - Returns a pointer to the rpc interface found which
|
|||
|
supports the requested interface and one of the requested transfer
|
|||
|
syntaxes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - The requested interface exists and it supports at least
|
|||
|
one of the proposed transfer syntaxes. We are all set, now we
|
|||
|
can make remote procedure calls.
|
|||
|
|
|||
|
RPC_P_UNSUPPORTED_TRANSFER_SYNTAX - The requested interface exists,
|
|||
|
but it does not support any of the proposed transfer syntaxes.
|
|||
|
|
|||
|
RPC_P_UNSUPPORTED_INTERFACE - The requested interface is not supported
|
|||
|
by this rpc server.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
return Server->FindInterfaceTransfer(
|
|||
|
InterfaceIdentifier,
|
|||
|
ProposedTransferSyntaxes,
|
|||
|
NumberOfTransferSyntaxes,
|
|||
|
AcceptedTransferSyntax,
|
|||
|
RpcInterface,
|
|||
|
fIsInterfaceTransferPreferred,
|
|||
|
ProposedTransferSyntaxIndex,
|
|||
|
AvailableTransferSyntaxIndex);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BINDING_HANDLE *
|
|||
|
RPC_ADDRESS::InquireBinding (
|
|||
|
RPC_CHAR * LocalNetworkAddress
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
We need to return create and return a binding handle which can
|
|||
|
be used by a client to make remote procedure calls to this rpc
|
|||
|
address.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A newly created binding handle will be returned, inless an out
|
|||
|
of memory error occurs, in which case zero will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
DCE_BINDING * DceBinding;
|
|||
|
BINDING_HANDLE * BindingHandle;
|
|||
|
RPC_CHAR * DynamicEndpoint = 0;
|
|||
|
RPC_CHAR * PAPI * tmpPtr;
|
|||
|
|
|||
|
if(LocalNetworkAddress == 0)
|
|||
|
{
|
|||
|
LocalNetworkAddress = pNetworkAddressVector->NetworkAddresses[0];
|
|||
|
}
|
|||
|
|
|||
|
DceBinding = new DCE_BINDING(
|
|||
|
0,
|
|||
|
RpcProtocolSequence,
|
|||
|
LocalNetworkAddress,
|
|||
|
(StaticEndpointFlag != 0 ? Endpoint : 0),
|
|||
|
0,
|
|||
|
&Status);
|
|||
|
if ((DceBinding == 0)
|
|||
|
|| (Status != RPC_S_OK))
|
|||
|
{
|
|||
|
delete DceBinding;
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
if (StaticEndpointFlag == 0)
|
|||
|
{
|
|||
|
DynamicEndpoint = DuplicateString(Endpoint);
|
|||
|
if (DynamicEndpoint == 0)
|
|||
|
{
|
|||
|
delete DceBinding;
|
|||
|
return(0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BindingHandle = new SVR_BINDING_HANDLE(DceBinding, DynamicEndpoint, &Status);
|
|||
|
if (BindingHandle == 0)
|
|||
|
{
|
|||
|
delete DceBinding;
|
|||
|
}
|
|||
|
|
|||
|
return(BindingHandle);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ADDRESS::ServerStartingToListen (
|
|||
|
IN unsigned int MinimumCallThreads,
|
|||
|
IN unsigned int MaximumConcurrentCalls
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This method will be called for each address when the server starts
|
|||
|
listening. In addition, if an address is added while the server is
|
|||
|
listening, then this method will be called. The purpose of the method
|
|||
|
is to notify the address about the minimum number of call threads
|
|||
|
required; the maximum concurrent calls can safely be ignored, but it
|
|||
|
can be used to set an upper bound on the number of call threads.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
MinimumCallThreads - Supplies a number indicating the minimum number
|
|||
|
of call threads which should be created for this address.
|
|||
|
|
|||
|
MaximumConcurrentCalls - Supplies the maximum number of concurrent
|
|||
|
calls which this server will support.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK - This routine will always return this value. Protocol
|
|||
|
support modules may return other values.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNUSED(MinimumCallThreads);
|
|||
|
UNUSED(MaximumConcurrentCalls);
|
|||
|
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
RPC_ADDRESS::ServerStoppedListening (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will be called to notify an address that the server has
|
|||
|
stopped listening for remote procedure calls. Each protocol module
|
|||
|
may override this routine; it is safe not too, but not as efficient.
|
|||
|
Note that this routine will be called before all calls using the
|
|||
|
server have been allowed to complete.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
long
|
|||
|
RPC_ADDRESS::InqNumberOfActiveCalls (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Each protocol module will define this routine. We will use this
|
|||
|
functionality when the server has stopped listening and is waiting
|
|||
|
for all remote procedure calls to complete. The number of active calls
|
|||
|
for the address will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
return(ActiveCallCount);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
RPC_ADDRESS::RestartAddress (
|
|||
|
IN unsigned int MinThreads,
|
|||
|
IN unsigned int MaxCalls
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
int Key;
|
|||
|
|
|||
|
Status = ServerSetupAddress(
|
|||
|
NetworkAddress,
|
|||
|
&Endpoint,
|
|||
|
PendingQueueSize,
|
|||
|
SecurityDescriptor,
|
|||
|
EndpointFlags,
|
|||
|
NICFlags,
|
|||
|
&pNetworkAddressVector);
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
pNetworkAddressVector = NULL;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Key = Server->AddAddress(this);
|
|||
|
if (Key == -1)
|
|||
|
{
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
Server->ServerMutex.Request();
|
|||
|
Status = ServerStartingToListen(MinThreads, MaxCalls);
|
|||
|
Server->ServerMutex.Clear();
|
|||
|
|
|||
|
|
|||
|
if (Status != RPC_S_OK)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
CompleteListen();
|
|||
|
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
RPC_ADDRESS::DestroyContextHandlesForInterface (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * ,
|
|||
|
IN BOOL
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: DestroyContextHandlesForInterface
|
|||
|
|
|||
|
Parameters:
|
|||
|
RpcInterfaceInformation - the interface for which context handles
|
|||
|
are to be unregistered
|
|||
|
RundownContextHandles - if non-zero, rundown the context handles. If
|
|||
|
FALSE, destroy the runtime portion of the context handle resource,
|
|||
|
but don't call the user rundown routine.
|
|||
|
|
|||
|
Description:
|
|||
|
Each protocol engine will implement its own version of this routine,
|
|||
|
if it supports the feature. For those who don't, this routine provides
|
|||
|
default no-op behaviour
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
RPC_ADDRESS::CleanupIdleSContexts (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: CleanupIdleSContexts
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
Description:
|
|||
|
Each protocol engine will implement its own version of this routine,
|
|||
|
if it supports the feature. For those who don't, this routine provides
|
|||
|
default no-op behaviour
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*====================================================================
|
|||
|
|
|||
|
SCONNECTION
|
|||
|
|
|||
|
==================================================================== */
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
SetThreadSecurityContext(
|
|||
|
SECURITY_CONTEXT * Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
RpcImpersonateClient() takes a handle_t, so many threads can impersonate
|
|||
|
the client of a single SCONNECTION. RPC needs to record which context
|
|||
|
each thread is using. It is logical to place this in the TLS, but threads
|
|||
|
not created by RPC lack the THREAD structure in their TLS. This wrapper
|
|||
|
function will store the security context in the TLS if available, or
|
|||
|
place the context in a dictionary if not.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - the security context to associate with this thread
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK if successful
|
|||
|
RPC_S_OUT_OF_MEMORY if the dictionary insertion failed
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
THREAD * ThreadInfo = ThreadSelf();
|
|||
|
|
|||
|
if (ThreadInfo)
|
|||
|
{
|
|||
|
ThreadInfo->SecurityContext = Context;
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
return RPC_S_OUT_OF_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
SECURITY_CONTEXT *
|
|||
|
QueryThreadSecurityContext(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Fetches the security context associated with this thread for this
|
|||
|
connection. We check the TLS if available; if nothing is there
|
|||
|
then we scan the connection's dictionary.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
the associated security context, or zero if none is found
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
THREAD * ThreadInfo = ThreadSelf();
|
|||
|
|
|||
|
if (ThreadInfo)
|
|||
|
{
|
|||
|
if (ThreadInfo->SecurityContext)
|
|||
|
{
|
|||
|
return (SECURITY_CONTEXT *) ThreadInfo->SecurityContext;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
SECURITY_CONTEXT *
|
|||
|
ClearThreadSecurityContext(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Clears the association between this thread and its security context
|
|||
|
for this connection.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
none
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
the formerly associated security context, or zero if none was found
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
THREAD * ThreadInfo = ThreadSelf();
|
|||
|
|
|||
|
if (ThreadInfo)
|
|||
|
{
|
|||
|
SECURITY_CONTEXT * Context =
|
|||
|
(SECURITY_CONTEXT *) ThreadInfo->SecurityContext;
|
|||
|
|
|||
|
if (Context)
|
|||
|
{
|
|||
|
ThreadInfo->SecurityContext = 0;
|
|||
|
return Context;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
SCALL::ImpersonateClient (
|
|||
|
)
|
|||
|
// This routine just returns RPC_CANNOT_SUPPORT indicating that this
|
|||
|
// particular connection does not support impersonation.
|
|||
|
{
|
|||
|
|
|||
|
ASSERT(0 && "improper SCALL member called\n");
|
|||
|
return(RPC_S_CANNOT_SUPPORT);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
SCALL::RevertToSelf (
|
|||
|
)
|
|||
|
// We always return RPC_CANNOT_SUPPORT indicating that the particular
|
|||
|
// connection does not support impersonation.
|
|||
|
{
|
|||
|
|
|||
|
ASSERT(0 && "improper SCALL member called\n");
|
|||
|
return(RPC_S_CANNOT_SUPPORT);
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
NDRSContextHandlePostDispatchProcessing (
|
|||
|
IN SCALL *SCall,
|
|||
|
ServerContextHandle *CtxHandle
|
|||
|
);
|
|||
|
|
|||
|
void
|
|||
|
SCALL::DoPostDispatchProcessing (
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
DictionaryCursor cursor;
|
|||
|
ServerContextHandle *CtxHandle;
|
|||
|
ServerContextHandle *RetrievedCtxHandle;
|
|||
|
int Key;
|
|||
|
|
|||
|
// the list will contain all in-only context
|
|||
|
// handles, as they don't get marshalled. It will also
|
|||
|
// contain the marshalling buffers for the newly
|
|||
|
// created context handles
|
|||
|
if (ActiveContextHandles.Size() > 0)
|
|||
|
{
|
|||
|
// no need to synchronize access to the
|
|||
|
// dictionary - only this call will be
|
|||
|
// touching it
|
|||
|
ActiveContextHandles.Reset(cursor);
|
|||
|
while ((CtxHandle = ActiveContextHandles.NextWithKey(cursor, &Key)) != 0)
|
|||
|
{
|
|||
|
// ignore buffers
|
|||
|
if ((ULONG_PTR)CtxHandle & SCALL::DictionaryEntryIsBuffer)
|
|||
|
{
|
|||
|
RetrievedCtxHandle = ActiveContextHandles.Delete(Key);
|
|||
|
ASSERT(RetrievedCtxHandle == CtxHandle);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// NDRSContextHandlePostDispatchProcessing will remove the context handle
|
|||
|
// from the dictionary - this doesn't interfere with our
|
|||
|
// enumeration
|
|||
|
NDRSContextHandlePostDispatchProcessing(this,
|
|||
|
CtxHandle
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
SCONNECTION::IsClientLocal (
|
|||
|
OUT unsigned int PAPI * ClientLocalFlag
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The connection oriented protocol module will override this method;
|
|||
|
all other protocol modules should just use this routine. We need this
|
|||
|
support so that the security system can tell if a client is local or
|
|||
|
remote.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientLocalFlag - Returns an indication of whether or not the client is
|
|||
|
local (ie. on the same machine as the server). This field will be
|
|||
|
set to a non-zero value to indicate that the client is local;
|
|||
|
otherwise, the client is remote.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_CANNOT_SUPPORT - This will always be used.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNUSED(ClientLocalFlag);
|
|||
|
|
|||
|
ASSERT(0 && "improper SCALL member called\n");
|
|||
|
return(RPC_S_CANNOT_SUPPORT);
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
SCALL::CreateAndSaveAuthzContextFromToken (
|
|||
|
IN OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContextPlaceholder OPTIONAL,
|
|||
|
IN HANDLE ImpersonationToken,
|
|||
|
IN AUTHZ_RESOURCE_MANAGER_HANDLE AuthzResourceManager,
|
|||
|
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
|
|||
|
IN LUID Identifier,
|
|||
|
IN DWORD Flags,
|
|||
|
IN PVOID DynamicGroupArgs OPTIONAL,
|
|||
|
OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates an Authz context from token. If saving is requested, it
|
|||
|
tries to save it in a thread-safe manner and duplicates it before
|
|||
|
returning. If saving is not requested, the resulting authz context
|
|||
|
is simply returned. In both cases caller owns the returned auth
|
|||
|
context.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pAuthzClientContextPlaceholder - contains a pointer to an authz placeholder.
|
|||
|
If NULL, out of the ImpersonationToken an authz context will
|
|||
|
be made and will be returned. If non-NULL, it must contain
|
|||
|
NULL. In this case an authz context will be created from the token,
|
|||
|
and it will be stored in the placeholder in a thread safe manner and a
|
|||
|
duplicate will be made and returned in pAuthzClientContext.
|
|||
|
ImpersonationToken - the impersonation token to use.
|
|||
|
AuthzResourceManager - authz parameters (not interpreted)
|
|||
|
pExpirationTime - authz parameters (not interpreted)
|
|||
|
Identifier - authz parameters (not interpreted)
|
|||
|
Flags - authz parameters (not interpreted)
|
|||
|
DynamicGroupArgs - authz parameters (not interpreted)
|
|||
|
pAuthzClientContext - contains the output authz context on success
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error code. EEInfo has been added.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
BOOL Result;
|
|||
|
AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext;
|
|||
|
|
|||
|
Result = AuthzInitializeContextFromTokenFn(
|
|||
|
Flags,
|
|||
|
ImpersonationToken,
|
|||
|
AuthzResourceManager,
|
|||
|
pExpirationTime,
|
|||
|
Identifier,
|
|||
|
DynamicGroupArgs,
|
|||
|
&AuthzClientContext);
|
|||
|
|
|||
|
if (!Result)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCAuthz,
|
|||
|
Status,
|
|||
|
EEInfoDLSCALL__CreateAndSaveAuthzContextFromToken10,
|
|||
|
GetCurrentThreadId(),
|
|||
|
(ULONGLONG)AuthzResourceManager);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (pAuthzClientContextPlaceholder)
|
|||
|
{
|
|||
|
if (InterlockedCompareExchangePointer((PVOID *)pAuthzClientContextPlaceholder,
|
|||
|
AuthzClientContext,
|
|||
|
NULL) != NULL)
|
|||
|
{
|
|||
|
// somebody beat us to the punch - free the context we obtained
|
|||
|
AuthzFreeContextFn(AuthzClientContext);
|
|||
|
// use the context that has been provided
|
|||
|
AuthzClientContext = *pAuthzClientContextPlaceholder;
|
|||
|
}
|
|||
|
|
|||
|
Status = DuplicateAuthzContext(AuthzClientContext,
|
|||
|
pExpirationTime,
|
|||
|
Identifier,
|
|||
|
Flags,
|
|||
|
DynamicGroupArgs,
|
|||
|
pAuthzClientContext);
|
|||
|
|
|||
|
if (Status)
|
|||
|
{
|
|||
|
// EEInfo has already been added
|
|||
|
return Status;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
*pAuthzClientContext = AuthzClientContext;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
SCALL::DuplicateAuthzContext (
|
|||
|
IN AUTHZ_CLIENT_CONTEXT_HANDLE AuthzClientContext,
|
|||
|
IN PLARGE_INTEGER pExpirationTime OPTIONAL,
|
|||
|
IN LUID Identifier,
|
|||
|
IN DWORD Flags,
|
|||
|
IN PVOID DynamicGroupArgs OPTIONAL,
|
|||
|
OUT PAUTHZ_CLIENT_CONTEXT_HANDLE pAuthzClientContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Take an Authz context, and make a duplicate of it, using the
|
|||
|
specified parameters. This method is a wrapper for
|
|||
|
AuthzInitializeContextFromContext, mainly adding error handling.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AuthzClientContext - source authz context
|
|||
|
pExpirationTime - authz parameters (not interpreted)
|
|||
|
Identifier - authz parameters (not interpreted)
|
|||
|
Flags - authz parameters (not interpreted)
|
|||
|
DynamicGroupArgs - authz parameters (not interpreted)
|
|||
|
pAuthzClientContext - target authz context pointer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Win32 error code.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status;
|
|||
|
BOOL Result;
|
|||
|
|
|||
|
// Copy the authz context. We must do a copy,
|
|||
|
// to avoid lifetime issues b/n our copy
|
|||
|
// and the client copy
|
|||
|
Result = AuthzInitializeContextFromAuthzContextFn(
|
|||
|
Flags,
|
|||
|
AuthzClientContext,
|
|||
|
pExpirationTime,
|
|||
|
Identifier,
|
|||
|
DynamicGroupArgs,
|
|||
|
pAuthzClientContext);
|
|||
|
|
|||
|
if (!Result)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
|
|||
|
RpcpErrorAddRecord(EEInfoGCAuthz,
|
|||
|
Status,
|
|||
|
EEInfoDLSCALL__DuplicateAuthzContext10,
|
|||
|
GetCurrentThreadId(),
|
|||
|
(ULONGLONG)AuthzClientContext);
|
|||
|
}
|
|||
|
else
|
|||
|
Status = RPC_S_OK;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* ====================================================================
|
|||
|
|
|||
|
ASSOCIATION_HANDLE :
|
|||
|
|
|||
|
==================================================================== */
|
|||
|
|
|||
|
static long AssociationIdCount = 0L;
|
|||
|
|
|||
|
void
|
|||
|
DestroyContextCollection (
|
|||
|
IN ContextCollection *CtxCollection
|
|||
|
);
|
|||
|
|
|||
|
ASSOCIATION_HANDLE::ASSOCIATION_HANDLE (
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
CtxCollection = NULL;
|
|||
|
AssociationID = InterlockedIncrement(&AssociationIdCount);
|
|||
|
}
|
|||
|
|
|||
|
ASSOCIATION_HANDLE::~ASSOCIATION_HANDLE (
|
|||
|
)
|
|||
|
// We finally get to use the rundown routines for somethings. The association
|
|||
|
// is being deleted which is the event that the rundown routines were waiting
|
|||
|
// for.
|
|||
|
{
|
|||
|
FireRundown();
|
|||
|
}
|
|||
|
|
|||
|
// Returns the context handle collection for this association.
|
|||
|
RPC_STATUS
|
|||
|
ASSOCIATION_HANDLE::GetAssociationContextCollection (
|
|||
|
ContextCollection **CtxCollectionPlaceholder
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: GetAssociationContextCollection
|
|||
|
|
|||
|
Parameters:
|
|||
|
CtxCollectionPlaceholder - a placeholder where to put the pointer to
|
|||
|
the context collection.
|
|||
|
|
|||
|
Description:
|
|||
|
The context handle code will call the SCALL to get the collection
|
|||
|
of context handles for this association. The SCALL method will
|
|||
|
simply delegate to this.
|
|||
|
This routine will check if the context handle collection was created
|
|||
|
and if so, it will just return it. If it wasn't created, it will try
|
|||
|
to create it.
|
|||
|
|
|||
|
Returns:
|
|||
|
RPC_S_OK for success or RPC_S_* for error.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
|
|||
|
if (CtxCollection)
|
|||
|
{
|
|||
|
*CtxCollectionPlaceholder = CtxCollection;
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = NDRSContextInitializeCollection(&CtxCollection);
|
|||
|
if (RpcStatus != RPC_S_OK)
|
|||
|
return RpcStatus;
|
|||
|
|
|||
|
*CtxCollectionPlaceholder = CtxCollection;
|
|||
|
return RpcStatus;
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
ASSOCIATION_HANDLE::FireRundown (
|
|||
|
void
|
|||
|
)
|
|||
|
{
|
|||
|
int nRetries = 20;
|
|||
|
RPC_STATUS status;
|
|||
|
|
|||
|
if (CtxCollection)
|
|||
|
{
|
|||
|
// make a best effort to make sure there is another listening thread
|
|||
|
// besides this one. If we repeatedly fail, we fire the rundown
|
|||
|
// anyway - currently few servers use outgoing RPC callbacks into the
|
|||
|
// same process, so we'd rather risk an unlikely deadlock than cause
|
|||
|
// a sure leak
|
|||
|
while (nRetries > 0)
|
|||
|
{
|
|||
|
status = CreateThread();
|
|||
|
if (status == RPC_S_OK)
|
|||
|
break;
|
|||
|
Sleep(10);
|
|||
|
nRetries --;
|
|||
|
}
|
|||
|
DestroyContextCollection(CtxCollection);
|
|||
|
if (status == RPC_S_OK)
|
|||
|
RundownNotificationCompleted();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// do nothing in the base case
|
|||
|
RPC_STATUS ASSOCIATION_HANDLE::CreateThread(void)
|
|||
|
{
|
|||
|
return RPC_S_OK;
|
|||
|
}
|
|||
|
|
|||
|
void ASSOCIATION_HANDLE::RundownNotificationCompleted(void)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
ASSOCIATION_HANDLE::DestroyContextHandlesForInterface (
|
|||
|
IN RPC_SERVER_INTERFACE PAPI * RpcInterfaceInformation,
|
|||
|
IN BOOL RundownContextHandles
|
|||
|
)
|
|||
|
/*++
|
|||
|
Function Name: DestroyContextHandlesForInterface
|
|||
|
|
|||
|
Parameters:
|
|||
|
RpcInterfaceInformation - the interface for which context handles
|
|||
|
are to be unregistered
|
|||
|
RundownContextHandles - if non-zero, rundown the context handles. If
|
|||
|
FALSE, destroy the runtime portion of the context handle resource,
|
|||
|
but don't call the user rundown routine.
|
|||
|
|
|||
|
Description:
|
|||
|
The association will call into NDR to destroy the specified context
|
|||
|
handles. It will either have a reference on the association, or the
|
|||
|
association mutex. Both ways, we're safe from destruction, and NDR
|
|||
|
will synchronize access to the list internally. The address has made
|
|||
|
a best effort not to hold the association mutex. If memory is low,
|
|||
|
it may end up doing so, however.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ContextCollection *LocalCtxCollection;
|
|||
|
void *pGuard;
|
|||
|
|
|||
|
// N.B. An association mutex may be held on entry for this
|
|||
|
// function. The server mutex may be held as well
|
|||
|
|
|||
|
LocalCtxCollection = CtxCollection;
|
|||
|
|
|||
|
// shortcut the common path
|
|||
|
if (!LocalCtxCollection)
|
|||
|
return;
|
|||
|
|
|||
|
pGuard = &RpcInterfaceInformation->InterfaceId;
|
|||
|
|
|||
|
// call into NDR to destroy the context handles
|
|||
|
DestroyContextHandlesForGuard(LocalCtxCollection,
|
|||
|
RundownContextHandles,
|
|||
|
pGuard);
|
|||
|
}
|
|||
|
|
|||
|
/* ====================================================================
|
|||
|
|
|||
|
Routine to initialize the server DLL.
|
|||
|
|
|||
|
==================================================================== */
|
|||
|
|
|||
|
int
|
|||
|
InitializeServerDLL (
|
|||
|
)
|
|||
|
{
|
|||
|
GetMaxRpcSizeAndThreadPoolParameters();
|
|||
|
|
|||
|
if (InitializeClientDLL() != 0)
|
|||
|
return(1);
|
|||
|
|
|||
|
#if 0
|
|||
|
if (InitializeSTransports() != 0)
|
|||
|
return(1);
|
|||
|
#endif
|
|||
|
|
|||
|
if (InitializeObjectDictionary() != 0)
|
|||
|
return(1);
|
|||
|
|
|||
|
if (InitializeRpcServer() != 0)
|
|||
|
return(1);
|
|||
|
|
|||
|
if (InitializeRpcProtocolLrpc() != 0)
|
|||
|
return(1);
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
void
|
|||
|
RpcpInterfaceForCallDoesNotUseStrict (
|
|||
|
IN RPC_BINDING_HANDLE BindingHandle
|
|||
|
)
|
|||
|
{
|
|||
|
SCALL *SCall;
|
|||
|
|
|||
|
if (((MESSAGE_OBJECT *)BindingHandle)->Type(SCALL_TYPE))
|
|||
|
{
|
|||
|
SCall = (SCALL *)BindingHandle;
|
|||
|
SCall->InterfaceForCallDoesNotUseStrict();
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
InqLocalConnAddress (
|
|||
|
IN SCALL *SCall,
|
|||
|
IN OUT void *Buffer,
|
|||
|
IN OUT unsigned long *BufferSize,
|
|||
|
OUT unsigned long *AddressFormat
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used by a server application to inquire about the local
|
|||
|
address on which a call is made.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Binding - Supplies a valid server binding. The binding must have been
|
|||
|
verified to be an SCALL by the caller.
|
|||
|
|
|||
|
Buffer - The buffer that will receive the output address
|
|||
|
|
|||
|
BufferSize - the size of the supplied Buffer on input. On output the
|
|||
|
number of bytes written to the buffer. If the buffer is too small
|
|||
|
to receive all the output data, ERROR_MORE_DATA is returned,
|
|||
|
nothing is written to the buffer, and BufferSize is set to
|
|||
|
the size of the buffer needed to return all the data.
|
|||
|
|
|||
|
AddressFormat - a constant indicating the format of the returned address.
|
|||
|
Currently supported are RPC_P_ADDR_FORMAT_TCP_IPV4 and
|
|||
|
RPC_P_ADDR_FORMAT_TCP_IPV6.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
RPC_S_OK - success.
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete this
|
|||
|
operation.
|
|||
|
|
|||
|
RPC_S_INVALID_BINDING - The supplied client binding is invalid.
|
|||
|
|
|||
|
RPC_S_CANNOT_SUPPORT - The local address was inquired for a protocol
|
|||
|
sequence that doesn't support this type of functionality. Currently
|
|||
|
only ncacn_ip_tcp supports it.
|
|||
|
|
|||
|
RPC_S_* or Win32 error for other errors
|
|||
|
--*/
|
|||
|
{
|
|||
|
// is this an osf scall?
|
|||
|
if (!SCall->InvalidHandle(OSF_SCALL_TYPE))
|
|||
|
{
|
|||
|
OSF_SCALL *OsfSCall;
|
|||
|
|
|||
|
OsfSCall = (OSF_SCALL *)SCall;
|
|||
|
|
|||
|
return OsfSCall->InqLocalConnAddress(
|
|||
|
Buffer,
|
|||
|
BufferSize,
|
|||
|
AddressFormat);
|
|||
|
}
|
|||
|
else if (!SCall->InvalidHandle(DG_SCALL_TYPE))
|
|||
|
{
|
|||
|
// this is a dg call
|
|||
|
DG_SCALL *DgSCall;
|
|||
|
|
|||
|
DgSCall = (DG_SCALL *)SCall;
|
|||
|
|
|||
|
return DgSCall->InqLocalConnAddress(
|
|||
|
Buffer,
|
|||
|
BufferSize,
|
|||
|
AddressFormat);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// the others don't support it
|
|||
|
return RPC_S_CANNOT_SUPPORT;
|
|||
|
}
|
|||
|
}
|
|||
|
|