1501 lines
45 KiB
C++
1501 lines
45 KiB
C++
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
Copyright (c) 1996-2000 Microsoft Corporation
|
||
|
||
Module Name :
|
||
|
||
async.c
|
||
|
||
Abstract :
|
||
|
||
This file contains the ndr async implementation.
|
||
|
||
Author :
|
||
|
||
Ryszard K. Kott (ryszardk) Nov 1996
|
||
|
||
Revision History :
|
||
|
||
---------------------------------------------------------------------*/
|
||
|
||
|
||
|
||
#define USE_STUBLESS_PROXY
|
||
|
||
#define CINTERFACE
|
||
|
||
#include "ndrp.h"
|
||
#include "ndrole.h"
|
||
#include "rpcproxy.h"
|
||
#include "hndl.h"
|
||
#include "interp.h"
|
||
#include "interp2.h"
|
||
#include "pipendr.h"
|
||
#include "mulsyntx.h"
|
||
#include "asyncndr.h"
|
||
#include "attack.h"
|
||
#include <stdarg.h>
|
||
|
||
#pragma code_seg(".orpc")
|
||
|
||
#ifdef _PPC_
|
||
#error PPC code has been removed
|
||
#endif
|
||
|
||
|
||
|
||
CLIENT_CALL_RETURN RPC_VAR_ENTRY
|
||
NdrAsyncClientCall(
|
||
PMIDL_STUB_DESC pStubDescriptor,
|
||
PFORMAT_STRING pFormat,
|
||
...
|
||
)
|
||
/*
|
||
This entry is used for raw rpc only.
|
||
No support for OLE [async] attribute anymore.
|
||
*/
|
||
{
|
||
va_list ArgList;
|
||
unsigned char * StartofStack;
|
||
CLIENT_CALL_RETURN Ret;
|
||
//
|
||
// Get address of argument to this function following pFormat. This
|
||
// is the address of the address of the first argument of the function
|
||
// calling this function.
|
||
// Then get the address of the stack where the parameters are.
|
||
//
|
||
|
||
RPC_ASYNC_HANDLE AsyncHandle;
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg;
|
||
|
||
RPC_MESSAGE * pRpcMsg;
|
||
MIDL_STUB_MESSAGE * pStubMsg;
|
||
ulong ProcNum, RpcFlags;
|
||
|
||
handle_t Handle;
|
||
uchar HandleType;
|
||
INTERPRETER_FLAGS OldOiFlags;
|
||
INTERPRETER_OPT_FLAGS NewOiFlags;
|
||
PPARAM_DESCRIPTION Params;
|
||
|
||
RPC_STATUS Status;
|
||
NDR_PROC_CONTEXT *pContext;
|
||
|
||
Ret.Simple = 0;
|
||
|
||
INIT_ARG( ArgList, pFormat);
|
||
GET_FIRST_IN_ARG(ArgList);
|
||
StartofStack = (uchar *) GET_STACK_START(ArgList);
|
||
|
||
pAsyncMsg = (NDR_ASYNC_MESSAGE*) I_RpcBCacheAllocate( sizeof( NDR_ASYNC_MESSAGE) );
|
||
if ( ! pAsyncMsg )
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
else
|
||
{
|
||
memset( pAsyncMsg, 0, sizeof( NDR_ASYNC_MESSAGE ) );
|
||
ProcNum = MulNdrpInitializeContextFromProc(
|
||
XFER_SYNTAX_DCE,
|
||
pFormat,
|
||
&pAsyncMsg->ProcContext,
|
||
NULL ); // server StartofStack
|
||
|
||
Status = NdrpInitializeAsyncMsg(
|
||
StartofStack,
|
||
pAsyncMsg );
|
||
}
|
||
|
||
if ( Status )
|
||
{
|
||
// if something is wrong during setup, we need to cleanup
|
||
// immediately. We have to process format string here explicitly
|
||
NDR_PROC_CONTEXT TempContext;
|
||
MIDL_STUB_MESSAGE StubMsgTemp;
|
||
ProcNum = MulNdrpInitializeContextFromProc(
|
||
XFER_SYNTAX_DCE,
|
||
pFormat,
|
||
&TempContext,
|
||
NULL ); // server StartofStack
|
||
|
||
OldOiFlags = TempContext.NdrInfo.InterpreterFlags;
|
||
if ( OldOiFlags.HasCommOrFault )
|
||
{
|
||
|
||
// It's easier to map the error here than to go through the error
|
||
// recovery and normal cleanup without valid handle etc.
|
||
|
||
StubMsgTemp.StubDesc = pStubDescriptor;
|
||
StubMsgTemp.StackTop = StartofStack;
|
||
|
||
NdrClientMapCommFault( & StubMsgTemp,
|
||
ProcNum,
|
||
Status,
|
||
(ULONG_PTR*) &Ret.Simple );
|
||
return Ret;
|
||
}
|
||
else
|
||
RpcRaiseException( Status );
|
||
}
|
||
|
||
pContext = &pAsyncMsg->ProcContext;
|
||
HandleType = pContext->HandleType;
|
||
NewOiFlags = pContext->NdrInfo.pProcDesc->Oi2Flags;
|
||
OldOiFlags = pContext->NdrInfo.InterpreterFlags;
|
||
Params = (PARAM_DESCRIPTION *)pContext->Params;
|
||
|
||
// We need to switch to our copy of the stack everywhere, including pStubMsg.
|
||
|
||
StartofStack = pAsyncMsg->ProcContext.StartofStack;
|
||
|
||
// We abstract the level of indirection here.
|
||
|
||
AsyncHandle = pAsyncMsg->AsyncHandle;
|
||
|
||
pRpcMsg = & pAsyncMsg->RpcMsg;
|
||
pStubMsg = & pAsyncMsg->StubMsg;
|
||
|
||
//
|
||
// Set Params and NumberParams before a call to initialization.
|
||
//
|
||
|
||
// Wrap everything in a try-finally pair. The finally clause does the
|
||
// required freeing of resources (RpcBuffer and Full ptr package).
|
||
//
|
||
RpcTryFinally
|
||
{
|
||
// Use a nested try-except pair to support [comm_status][fault_status].
|
||
//
|
||
RpcTryExcept
|
||
{
|
||
BOOL fRaiseExcFlag;
|
||
|
||
NdrClientInitializeNew( pRpcMsg,
|
||
pStubMsg,
|
||
pStubDescriptor,
|
||
(uint) ProcNum );
|
||
|
||
if ( HandleType )
|
||
{
|
||
//
|
||
// We have an implicit handle.
|
||
//
|
||
Handle = ImplicitBindHandleMgr( pStubDescriptor,
|
||
HandleType,
|
||
&pContext->SavedGenericHandle);
|
||
}
|
||
else
|
||
{
|
||
Handle = ExplicitBindHandleMgr( pStubDescriptor,
|
||
StartofStack,
|
||
(PFORMAT_STRING)pContext->pHandleFormatSave,
|
||
&pContext->SavedGenericHandle );
|
||
}
|
||
|
||
pStubMsg->pAsyncMsg = pAsyncMsg;
|
||
|
||
NdrpClientInit( pStubMsg,
|
||
NULL ); // return value
|
||
|
||
|
||
//
|
||
// Skip buffer size pass if possible.
|
||
//
|
||
if ( NewOiFlags.ClientMustSize )
|
||
{
|
||
NdrpSizing( pStubMsg,
|
||
TRUE ); // isclient
|
||
}
|
||
|
||
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
||
|
||
if ( NewOiFlags.HasPipes )
|
||
NdrGetPipeBuffer( pStubMsg,
|
||
pStubMsg->BufferLength,
|
||
Handle );
|
||
else
|
||
NdrGetBuffer( pStubMsg,
|
||
pStubMsg->BufferLength,
|
||
Handle );
|
||
|
||
NDR_ASSERT( pStubMsg->fBufferValid, "Invalid buffer" );
|
||
|
||
// Let runtime associate async handle with the call.
|
||
|
||
NdrpRegisterAsyncHandle( pStubMsg, AsyncHandle );
|
||
|
||
pAsyncMsg->StubPhase = NDR_ASYNC_SET_PHASE;
|
||
|
||
//
|
||
// ----------------------------------------------------------
|
||
// Marshall Pass.
|
||
// ----------------------------------------------------------
|
||
//
|
||
|
||
NdrpClientMarshal( pStubMsg,
|
||
FALSE ); // IsObject
|
||
|
||
pAsyncMsg->StubPhase = NDR_ASYNC_CALL_PHASE;
|
||
|
||
NdrAsyncSend( pStubMsg,
|
||
NewOiFlags.HasPipes && pContext->pPipeDesc->InPipes );
|
||
|
||
pAsyncMsg->Flags.ValidCallPending = 1;
|
||
}
|
||
RpcExcept( OldOiFlags.HasCommOrFault )
|
||
{
|
||
RPC_STATUS ExceptionCode = RpcExceptionCode();
|
||
|
||
// Actually dismantle the call.
|
||
// This is a request call and there is nothing left at the runtime.
|
||
|
||
pAsyncMsg->StubPhase = NDR_ASYNC_ERROR_PHASE;
|
||
|
||
NdrClientMapCommFault( pStubMsg,
|
||
ProcNum,
|
||
ExceptionCode,
|
||
(ULONG_PTR*) &Ret.Simple );
|
||
}
|
||
RpcEndExcept
|
||
}
|
||
RpcFinally
|
||
{
|
||
if ( pAsyncMsg->Flags.ValidCallPending )
|
||
{
|
||
if ( NewOiFlags.HasPipes )
|
||
{
|
||
NdrMarkNextActivePipe( pContext->pPipeDesc );
|
||
pContext->pPipeDesc->Flags.NoBufferCallPending = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Cleanup everything but the user's handle.
|
||
|
||
NdrpFreeAsyncMsg( pAsyncMsg );
|
||
|
||
AsyncHandle->StubInfo = 0;
|
||
}
|
||
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
}
|
||
RpcEndFinally
|
||
|
||
return Ret;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NdrpCompleteAsyncClientCall(
|
||
RPC_ASYNC_HANDLE AsyncHandle,
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
void * pReturnValue
|
||
)
|
||
{
|
||
RPC_MESSAGE * pRpcMsg = & pAsyncMsg->RpcMsg;
|
||
MIDL_STUB_MESSAGE * pStubMsg = & pAsyncMsg->StubMsg;
|
||
|
||
PFORMAT_STRING pFormatParam;
|
||
NDR_PROC_CONTEXT * pContext = &pAsyncMsg->ProcContext;
|
||
NDR_PROC_INFO * pNdrInfo = &pContext->NdrInfo;
|
||
INTERPRETER_FLAGS OldOiFlags = pNdrInfo->InterpreterFlags;
|
||
INTERPRETER_OPT_FLAGS NewOiFlags = pNdrInfo->pProcDesc->Oi2Flags;
|
||
PPARAM_DESCRIPTION Params = (PPARAM_DESCRIPTION )pContext->Params;
|
||
uchar * StartofStack = pContext->StartofStack ;
|
||
|
||
PMIDL_STUB_DESC pStubDescriptor = pStubMsg->StubDesc;
|
||
ulong RpcFlags = pRpcMsg->RpcFlags;
|
||
|
||
ULONG_PTR RetVal = 0;
|
||
|
||
long NumberParams = pContext->NumberParams;
|
||
long n;
|
||
NDR_ASYNC_CALL_FLAGS CallFlags = pAsyncMsg->Flags;
|
||
|
||
RpcTryFinally
|
||
{
|
||
// Use a nested try-except pair to support [comm_status][fault_status].
|
||
//
|
||
RpcTryExcept
|
||
{
|
||
|
||
if ( ! CallFlags.ValidCallPending )
|
||
RpcRaiseException( RPC_S_INVALID_ASYNC_HANDLE );
|
||
|
||
CallFlags.ValidCallPending = 0;
|
||
|
||
// Non-pipe case or after pipe args case.
|
||
|
||
if ( NewOiFlags.HasPipes )
|
||
NdrIsAppDoneWithPipes( pContext->pPipeDesc );
|
||
|
||
NdrLastAsyncReceive( pStubMsg );
|
||
|
||
//
|
||
// ----------------------------------------------------------
|
||
// Unmarshall Pass.
|
||
// ----------------------------------------------------------
|
||
//
|
||
|
||
NdrpClientUnMarshal( pStubMsg,
|
||
(CLIENT_CALL_RETURN *)pReturnValue );
|
||
|
||
|
||
}
|
||
RpcExcept( OldOiFlags.HasCommOrFault )
|
||
{
|
||
RPC_STATUS ExceptionCode = RpcExceptionCode();
|
||
|
||
CallFlags.ValidCallPending = ExceptionCode == RPC_S_ASYNC_CALL_PENDING;
|
||
|
||
NdrClientMapCommFault( pStubMsg,
|
||
pRpcMsg->ProcNum,
|
||
ExceptionCode,
|
||
&RetVal );
|
||
|
||
if ( ExceptionCode == RPC_S_ASYNC_CALL_PENDING )
|
||
{
|
||
// If the call is just pending, force the pending error code
|
||
// to show up in the return value of RpcAsyncCallComplete.
|
||
|
||
RetVal = RPC_S_ASYNC_CALL_PENDING;
|
||
}
|
||
}
|
||
RpcEndExcept
|
||
|
||
}
|
||
RpcFinally
|
||
{
|
||
// There is only one way a valid call may be pending at this stage:
|
||
// that is the receive call returned with RPC_S_CALL_PENDING.
|
||
|
||
if ( ! CallFlags.ValidCallPending )
|
||
{
|
||
// Cleanup everything. However, don't free user's handle.
|
||
|
||
NdrpFreeAsyncMsg( pAsyncMsg );
|
||
|
||
AsyncHandle->StubInfo = 0;
|
||
}
|
||
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
}
|
||
RpcEndFinally
|
||
|
||
return (RPC_STATUS)RetVal;
|
||
}
|
||
|
||
|
||
void RPC_ENTRY
|
||
NdrAsyncServerCall(
|
||
PRPC_MESSAGE pRpcMsg
|
||
)
|
||
/*++
|
||
Routine Description :
|
||
|
||
The server side entry point for regular asynchronous RPC procs.
|
||
|
||
Arguments :
|
||
|
||
pRpcMsg - The RPC message.
|
||
|
||
Return :
|
||
|
||
None.
|
||
--*/
|
||
{
|
||
RPC_ASYNC_HANDLE AsyncHandle = 0;
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg;
|
||
|
||
PRPC_SERVER_INTERFACE pServerIfInfo;
|
||
PMIDL_SERVER_INFO pServerInfo;
|
||
PMIDL_STUB_DESC pStubDesc;
|
||
const SERVER_ROUTINE * DispatchTable;
|
||
ushort ProcNum;
|
||
|
||
ushort FormatOffset;
|
||
PFORMAT_STRING pFormat;
|
||
PFORMAT_STRING pFormatParam;
|
||
|
||
PMIDL_STUB_MESSAGE pStubMsg;
|
||
|
||
uchar * pArgBuffer;
|
||
uchar ** ppArg;
|
||
|
||
PPARAM_DESCRIPTION Params;
|
||
INTERPRETER_FLAGS OldOiFlags;
|
||
INTERPRETER_OPT_FLAGS NewOiFlags;
|
||
long NumberParams;
|
||
|
||
|
||
ushort ClientBufferSize;
|
||
BOOL HasExplicitHandle;
|
||
long n;
|
||
NDR_PROC_CONTEXT * pContext;
|
||
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
|
||
//
|
||
// In the case of a context handle, the server side manager function has
|
||
// to be called with NDRSContextValue(ctxthandle). But then we may need to
|
||
// marshall the handle, so NDRSContextValue(ctxthandle) is put in the
|
||
// argument buffer and the handle itself is stored in the following array.
|
||
// When marshalling a context handle, we marshall from this array.
|
||
//
|
||
// The handle table is part of the async handle.
|
||
|
||
ProcNum = (ushort) pRpcMsg->ProcNum;
|
||
|
||
NDR_ASSERT( ! ((ULONG_PTR)pRpcMsg->Buffer & 0x7),
|
||
"marshaling buffer misaligned at server" );
|
||
|
||
pServerIfInfo = (PRPC_SERVER_INTERFACE)pRpcMsg->RpcInterfaceInformation;
|
||
pServerInfo = (PMIDL_SERVER_INFO)pServerIfInfo->InterpreterInfo;
|
||
DispatchTable = pServerInfo->DispatchTable;
|
||
|
||
pStubDesc = pServerInfo->pStubDesc;
|
||
|
||
FormatOffset = pServerInfo->FmtStringOffset[ProcNum];
|
||
pFormat = &((pServerInfo->ProcString)[FormatOffset]);
|
||
|
||
|
||
AsyncHandle = 0;
|
||
pAsyncMsg = (NDR_ASYNC_MESSAGE*) I_RpcBCacheAllocate( sizeof( NDR_ASYNC_MESSAGE) );
|
||
if ( ! pAsyncMsg )
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
else
|
||
{
|
||
memset( pAsyncMsg, 0, sizeof( NDR_ASYNC_MESSAGE ) );
|
||
MulNdrpInitializeContextFromProc(
|
||
XFER_SYNTAX_DCE,
|
||
pFormat,
|
||
&pAsyncMsg->ProcContext,
|
||
NULL ); // server StartofStack
|
||
|
||
Status = NdrpInitializeAsyncMsg( 0, // StartofStack, server
|
||
pAsyncMsg
|
||
);
|
||
}
|
||
|
||
if ( Status )
|
||
RpcRaiseException( Status );
|
||
|
||
pAsyncMsg->StubPhase = STUB_UNMARSHAL;
|
||
|
||
pStubMsg = & pAsyncMsg->StubMsg;
|
||
|
||
// from Kamen:
|
||
// we don't need to copy RpcMsg : it's provided by runtime in server side
|
||
pContext = &pAsyncMsg->ProcContext;
|
||
// setup the type format string in old code.
|
||
pContext->DceTypeFormatString = pStubDesc->pFormatTypes;
|
||
|
||
pStubMsg->RpcMsg = pRpcMsg;
|
||
pStubMsg->SavedContextHandles = pAsyncMsg->CtxtHndl;
|
||
|
||
// The arg buffer is zeroed out already.
|
||
pArgBuffer = pAsyncMsg->ProcContext.StartofStack;
|
||
|
||
OldOiFlags = pContext->NdrInfo.InterpreterFlags;
|
||
NewOiFlags = pContext->NdrInfo.pProcDesc->Oi2Flags;
|
||
NumberParams = pContext->NumberParams;
|
||
Params = ( PPARAM_DESCRIPTION ) pContext->Params;
|
||
//
|
||
// Wrap the unmarshalling and the invoke call in the try block of
|
||
// a try-finally. Put the free phase in the associated finally block.
|
||
//
|
||
BOOL fManagerCodeInvoked = FALSE;
|
||
BOOL fErrorInInvoke = FALSE;
|
||
RPC_STATUS ExceptionCode = 0;
|
||
|
||
// We abstract the level of indirection here.
|
||
|
||
AsyncHandle = pAsyncMsg->AsyncHandle;
|
||
|
||
RpcTryFinally
|
||
{
|
||
RpcTryExcept
|
||
{
|
||
// Put the async handle on stack.
|
||
((void **)pArgBuffer)[0] = AsyncHandle;
|
||
|
||
NdrpServerInit( pStubMsg,
|
||
pRpcMsg,
|
||
pStubDesc,
|
||
NULL, // pThis
|
||
NULL, // pChannel
|
||
pAsyncMsg );
|
||
|
||
// Let runtime associate async handle with the call.
|
||
|
||
NdrpRegisterAsyncHandle( pStubMsg, AsyncHandle );
|
||
|
||
pAsyncMsg->StubPhase = NDR_ASYNC_SET_PHASE;
|
||
|
||
NdrpServerUnMarshal( pStubMsg );
|
||
|
||
if ( pRpcMsg->BufferLength <
|
||
(uint)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer) )
|
||
{
|
||
RpcRaiseException( RPC_X_BAD_STUB_DATA );
|
||
}
|
||
|
||
|
||
}
|
||
RpcExcept( NdrServerUnmarshallExceptionFlag(GetExceptionInformation()) )
|
||
{
|
||
ExceptionCode = RpcExceptionCode();
|
||
|
||
if( RPC_BAD_STUB_DATA_EXCEPTION_FILTER )
|
||
{
|
||
ExceptionCode = RPC_X_BAD_STUB_DATA;
|
||
}
|
||
|
||
// we always free the memory list if exception happened
|
||
// during unmarshalling. Exception code will tell if this
|
||
// is really RPC_X_BAD_STUB_DATA;
|
||
NdrpFreeMemoryList( pStubMsg );
|
||
pAsyncMsg->Flags.BadStubData = 1;
|
||
pAsyncMsg->ErrorCode = ExceptionCode;
|
||
RpcRaiseException( ExceptionCode );
|
||
}
|
||
RpcEndExcept
|
||
|
||
// Two separate blocks because the filters are different.
|
||
// We need to catch exception in the manager code separately
|
||
// as the model implies that there will be no other call from
|
||
// the server app to clean up.
|
||
|
||
RpcTryExcept
|
||
{
|
||
//
|
||
// Do [out] initialization before the invoke.
|
||
//
|
||
|
||
NdrpServerOutInit( pStubMsg );
|
||
|
||
//
|
||
// Unblock the first pipe; this needs to be after unmarshalling
|
||
// because the buffer may need to be changed to the secondary one.
|
||
// In the out only pipes case this happens immediately.
|
||
//
|
||
if ( NewOiFlags.HasPipes )
|
||
NdrMarkNextActivePipe( pContext->pPipeDesc );
|
||
|
||
pAsyncMsg->StubPhase = STUB_CALL_SERVER;
|
||
|
||
//
|
||
// Check for a thunk. Compiler does all the setup for us.
|
||
//
|
||
if ( pServerInfo->ThunkTable && pServerInfo->ThunkTable[ProcNum] )
|
||
{
|
||
pAsyncMsg->Flags.ValidCallPending = 1;
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
|
||
fManagerCodeInvoked = TRUE;
|
||
fErrorInInvoke = TRUE;
|
||
pServerInfo->ThunkTable[ProcNum]( pStubMsg );
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Note that this ArgNum is not the number of arguments declared
|
||
// in the function we called, but really the number of
|
||
// REGISTER_TYPEs occupied by the arguments to a function.
|
||
//
|
||
long ArgNum;
|
||
MANAGER_FUNCTION pFunc;
|
||
REGISTER_TYPE returnValue;
|
||
|
||
if ( pRpcMsg->ManagerEpv )
|
||
pFunc = ((MANAGER_FUNCTION *)pRpcMsg->ManagerEpv)[ProcNum];
|
||
else
|
||
pFunc = (MANAGER_FUNCTION) DispatchTable[ProcNum];
|
||
|
||
ArgNum = (long) pContext->StackSize / sizeof(REGISTER_TYPE);
|
||
|
||
//
|
||
// The StackSize includes the size of the return. If we want
|
||
// just the number of REGISTER_TYPES, then ArgNum must be reduced
|
||
// by 1 when there is a return value AND the current ArgNum count
|
||
// is greater than 0.
|
||
//
|
||
if ( ArgNum && NewOiFlags.HasReturn )
|
||
ArgNum--;
|
||
|
||
// Being here means that we can expect results. Note that the user
|
||
// can call RpcCompleteCall from inside of the manager code.
|
||
|
||
pAsyncMsg->Flags.ValidCallPending = 1;
|
||
|
||
// Unlock the handle - the app is allowed to call RpCAsyncManager
|
||
// or RpcAsyncAbort from the manager code.
|
||
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
|
||
fManagerCodeInvoked = TRUE;
|
||
fErrorInInvoke = TRUE;
|
||
|
||
returnValue = Invoke( pFunc,
|
||
(REGISTER_TYPE *)pArgBuffer,
|
||
#if defined(_IA64_)
|
||
NewOiFlags.HasExtensions ? ((PNDR_PROC_HEADER_EXTS64)&pContext->NdrInfo.pProcDesc->NdrExts)->FloatArgMask
|
||
: 0,
|
||
#endif
|
||
ArgNum);
|
||
|
||
// We are discarding the return value as it is not the real one.
|
||
// The real return value is passed in the complete call.
|
||
}
|
||
|
||
fErrorInInvoke = FALSE;
|
||
}
|
||
RpcExcept( 1 )
|
||
{
|
||
ExceptionCode = RpcExceptionCode();
|
||
|
||
if ( ExceptionCode == 0 )
|
||
ExceptionCode = ERROR_INVALID_PARAMETER;
|
||
|
||
// We may not have the async message around anymore.
|
||
|
||
RpcRaiseException( ExceptionCode );
|
||
}
|
||
RpcEndExcept
|
||
|
||
}
|
||
RpcFinally
|
||
{
|
||
if ( fManagerCodeInvoked && !fErrorInInvoke )
|
||
{
|
||
// Success. Just skip everything if the manager code was invoked
|
||
// and returned successfully.
|
||
// Note that manager code could have called Complete or Abort by now
|
||
// and so the async handle may not be valid anymore.
|
||
}
|
||
else
|
||
{
|
||
// See if we can clean up;
|
||
|
||
Status = RPC_S_OK;
|
||
if ( fErrorInInvoke )
|
||
{
|
||
// After an exception in invoking, let's see if we can get a hold
|
||
// of the handle. If so, we will be able to clean up.
|
||
// If not, there may be a leak there that we can do nothing about.
|
||
// The rule is: after an exception the app cannot call Abort or
|
||
// Complete. So, we need to force complete if we can.
|
||
|
||
Status = NdrValidateBothAndLockAsyncHandle( AsyncHandle );
|
||
}
|
||
|
||
if ( Status == RPC_S_OK )
|
||
{
|
||
// Something went wrong but we are able to do the cleanup.
|
||
|
||
// Cleanup parameters and async message/handle.
|
||
// propagate the exception.
|
||
|
||
NdrpCleanupServerContextHandles( pStubMsg,
|
||
pArgBuffer,
|
||
TRUE ); // die in manager routine
|
||
|
||
if (!pAsyncMsg->Flags.BadStubData)
|
||
{
|
||
NdrpFreeParams( pStubMsg,
|
||
NumberParams,
|
||
Params,
|
||
pArgBuffer );
|
||
}
|
||
|
||
NdrpFreeAsyncHandleAndMessage( AsyncHandle );
|
||
}
|
||
|
||
// else manager code invoked and we could not recover.
|
||
// Exception will be raised by the EndFinally below.
|
||
}
|
||
|
||
}
|
||
RpcEndFinally
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NdrpCompleteAsyncServerCall(
|
||
RPC_ASYNC_HANDLE AsyncHandle,
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
void * pReturnValue
|
||
)
|
||
/*++
|
||
|
||
Routine Description :
|
||
|
||
Complete an async call on the server side. If an exception occurs, the
|
||
asynchronous rpc call is aborted with the exception code and the server side
|
||
caller is returned S_OK.
|
||
|
||
Arguments :
|
||
|
||
AsyncHandle - validated asynchronous handle,
|
||
pAsyncMsg - pointer to async msg structure,
|
||
pReturnValue - pointer to the return value to be passed to the client.
|
||
|
||
Return :
|
||
|
||
Status of S_OK.
|
||
|
||
--*/
|
||
{
|
||
// in the server side, we don't use pAsyncMsg->RpcMsg. for Kamen
|
||
MIDL_STUB_MESSAGE * pStubMsg = & pAsyncMsg->StubMsg;
|
||
RPC_MESSAGE * pRpcMsg = pStubMsg->RpcMsg;
|
||
|
||
PFORMAT_STRING pFormatParam;
|
||
NDR_PROC_CONTEXT * pContext = & pAsyncMsg->ProcContext;
|
||
|
||
INTERPRETER_FLAGS OldOiFlags = pContext->NdrInfo.InterpreterFlags;
|
||
INTERPRETER_OPT_FLAGS NewOiFlags = pContext->NdrInfo.pProcDesc->Oi2Flags;
|
||
PPARAM_DESCRIPTION Params = ( PPARAM_DESCRIPTION )pContext->Params;
|
||
uchar * pArgBuffer = pContext->StartofStack;
|
||
unsigned long StackSize = pContext->StackSize;
|
||
PMIDL_STUB_DESC pStubDesc = pStubMsg->StubDesc;
|
||
|
||
long NumberParams = pContext->NumberParams;
|
||
long n;
|
||
boolean fParamsFreed = FALSE;
|
||
|
||
//
|
||
// Wrap the unmarshalling, mgr call and marshalling in the try block of
|
||
// a try-except. Put the call to abort in the except clause.
|
||
//
|
||
RpcTryExcept
|
||
{
|
||
// At this point, this is a valid RPC call since the asynchronous handle
|
||
// is owned by NDR on the server side and NDR passes the handle
|
||
// to the server during the invoke call. During invoke
|
||
// the parameters have already been unmarshalled.
|
||
|
||
pAsyncMsg->StubPhase = STUB_MARSHAL;
|
||
|
||
if( NewOiFlags.HasReturn )
|
||
{
|
||
// Put user's return value on the stack as usual.
|
||
// See the invoke for comments on folding return into the arg satck.
|
||
|
||
NDR_ASSERT( !pContext->HasComplexReturn, "complex return is not supported in async" );
|
||
|
||
long ArgNum = (long) StackSize / sizeof(REGISTER_TYPE);
|
||
|
||
if ( ArgNum )
|
||
ArgNum--;
|
||
|
||
if ( ! pReturnValue )
|
||
RpcRaiseException( RPC_S_INVALID_ARG );
|
||
|
||
// We don't support return value larger than register_type,
|
||
// and memcpy avoid alignment issue.
|
||
if ( Params[NumberParams-1].ParamAttr.IsBasetype )
|
||
memcpy( &((REGISTER_TYPE *)pArgBuffer)[ArgNum],
|
||
pReturnValue,
|
||
(size_t)SIMPLE_TYPE_MEMSIZE( Params[NumberParams-1].SimpleType.Type ) );
|
||
else
|
||
((REGISTER_TYPE *)pArgBuffer)[ArgNum] = *(REGISTER_TYPE*)pReturnValue;
|
||
}
|
||
|
||
//
|
||
// Buffer size pass.
|
||
//
|
||
ushort ConstantBufferSize = pContext->NdrInfo.pProcDesc->ServerBufferSize;
|
||
|
||
if ( NewOiFlags.HasPipes )
|
||
{
|
||
NdrIsAppDoneWithPipes( pContext->pPipeDesc );
|
||
pStubMsg->BufferLength += ConstantBufferSize;
|
||
}
|
||
else
|
||
pStubMsg->BufferLength = ConstantBufferSize;
|
||
|
||
if ( NewOiFlags.ServerMustSize )
|
||
{
|
||
NdrpSizing( pStubMsg,
|
||
FALSE ); // this is server
|
||
}
|
||
|
||
// Get buffer.
|
||
|
||
if ( NewOiFlags.HasPipes && pContext->pPipeDesc->OutPipes )
|
||
{
|
||
NdrGetPartialBuffer( pStubMsg );
|
||
pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_PARTIAL;
|
||
}
|
||
else
|
||
{
|
||
NdrGetBuffer( pStubMsg,
|
||
pStubMsg->BufferLength,
|
||
0 );
|
||
}
|
||
|
||
//
|
||
// Marshall pass.
|
||
//
|
||
NdrpServerMarshal( pStubMsg,
|
||
FALSE ); // IsObject
|
||
|
||
pRpcMsg->BufferLength = (ulong)(pStubMsg->Buffer - (uchar *)pRpcMsg->Buffer);
|
||
|
||
// We don't drop to the runtime like for synchronous calls,
|
||
// we send the last buffer explicitly.
|
||
|
||
// set the freed flag.
|
||
fParamsFreed = TRUE;
|
||
/*
|
||
we have to do release twice here:
|
||
After the last piece of data is sent via NdrAsyncSend, dispatch buffer
|
||
will be freed by runtime. We'll have problem calling ndr free routines to
|
||
free unique pointers (where both pointer and pointee are in the buffer). So
|
||
we call ndr free routines BEFORE the send, because it won't free anything
|
||
inside dispatch buffer, and runtime send only cares about dispatch buffer.
|
||
We still have to call ndr free routines in RpcFinally for exception cleanup. we
|
||
check the flag to avoid calling free twice.
|
||
*/
|
||
NdrpFreeParams( pStubMsg,
|
||
NumberParams,
|
||
Params,
|
||
pArgBuffer );
|
||
|
||
NdrAsyncSend( pStubMsg,
|
||
FALSE ); // the last call is always non-partial
|
||
}
|
||
RpcExcept(1)
|
||
{
|
||
|
||
// Abort the call which will result in the exception being propagated to
|
||
// the client.
|
||
|
||
NdrpAsyncAbortCall( AsyncHandle,
|
||
pAsyncMsg,
|
||
RpcExceptionCode(),
|
||
!fParamsFreed ); // Do not free if second attempt.
|
||
return S_OK;
|
||
}
|
||
RpcEndExcept
|
||
|
||
NdrpFreeAsyncHandleAndMessage( AsyncHandle );
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
NdrpInitializeAsyncMsg(
|
||
void * StartofStack,
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg )
|
||
/*
|
||
This method creates and initializes async msg.
|
||
Additionally, it creates the handle itself in object case.
|
||
|
||
pHandleArg - pointer to the proc's async handle argument.
|
||
Note the handle arg semantics on the client:
|
||
*pHandleArg is
|
||
raw: a handle (arg is a *)
|
||
- the handle cannot be 0
|
||
obj: a pHandle (arg is a **)
|
||
pHandle ==0 means a "don't care" call
|
||
*pHandle ==0 means "create handle while calling"
|
||
*pHandle !=0 means a handle created by the app.
|
||
|
||
StartofStack - side marker as well:
|
||
!= 0 - client
|
||
== 0 - server
|
||
*/
|
||
{
|
||
RPC_STATUS Status = 0;
|
||
BOOL fIsClient = StartofStack != 0;
|
||
BOOL fHandleCreated = FALSE;
|
||
RPC_ASYNC_HANDLE AsyncHandle = 0;
|
||
RPC_ASYNC_HANDLE * pHandleArg = (RPC_ASYNC_HANDLE *)StartofStack;
|
||
|
||
// Do this first to simplify error conditions.
|
||
|
||
|
||
ulong StackSize = pAsyncMsg->ProcContext.StackSize;
|
||
|
||
|
||
if ( fIsClient )
|
||
{
|
||
// Client always supplies a handle.
|
||
|
||
if ( *pHandleArg )
|
||
{
|
||
AsyncHandle = *pHandleArg;
|
||
Status = NdrpValidateAndLockAsyncHandle( AsyncHandle );
|
||
}
|
||
else
|
||
Status = RPC_S_INVALID_ASYNC_HANDLE;
|
||
}
|
||
else
|
||
{
|
||
// Server - the stub creates the handle.
|
||
|
||
AsyncHandle = (RPC_ASYNC_STATE *)I_RpcAllocate( sizeof(RPC_ASYNC_STATE) );
|
||
if ( ! AsyncHandle )
|
||
Status = RPC_S_OUT_OF_MEMORY;
|
||
else
|
||
{
|
||
MIDL_memset( AsyncHandle, 0x0, sizeof( RPC_ASYNC_STATE) );
|
||
RpcAsyncInitializeHandle( AsyncHandle, RPC_ASYNC_VERSION_1_0 );
|
||
AsyncHandle->Lock = 1;
|
||
fHandleCreated = TRUE;
|
||
}
|
||
}
|
||
|
||
if ( Status )
|
||
{
|
||
I_RpcBCacheFree( pAsyncMsg );
|
||
return Status;
|
||
}
|
||
|
||
// Initialize the async message properly
|
||
|
||
pAsyncMsg->Signature = NDR_ASYNC_SIGNATURE;
|
||
pAsyncMsg->Version = NDR_ASYNC_VERSION;
|
||
pAsyncMsg->StubMsg.pContext = & pAsyncMsg->ProcContext;
|
||
|
||
pAsyncMsg->ProcContext.StartofStack = (uchar *) NdrpAlloca(
|
||
& pAsyncMsg->ProcContext.AllocateContext,
|
||
StackSize );
|
||
|
||
// Must do this before the sizing pass!
|
||
pAsyncMsg->StubMsg.StackTop = (uchar *)StartofStack;
|
||
|
||
pAsyncMsg->StubPhase = NDR_ASYNC_PREP_PHASE;
|
||
|
||
if ( fIsClient )
|
||
{
|
||
// Client: copy stack from the app's request call.
|
||
RpcpMemoryCopy( pAsyncMsg->ProcContext.StartofStack, StartofStack, StackSize );
|
||
}
|
||
else
|
||
{
|
||
// Server: zero out stack for allocs.
|
||
MIDL_memset( pAsyncMsg->ProcContext.StartofStack, 0x0, StackSize );
|
||
}
|
||
|
||
MIDL_memset( pAsyncMsg->AsyncGuard,
|
||
0x71,
|
||
NDR_ASYNC_GUARD_SIZE );
|
||
|
||
AsyncHandle->StubInfo = pAsyncMsg;
|
||
pAsyncMsg->AsyncHandle = AsyncHandle;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
void
|
||
NdrpFreeAsyncMsg(
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg )
|
||
/*
|
||
This routine would free the AsyncMsg but not the AsyncHandle, as on the server
|
||
the user may need it and on the client it is user's to begin with.
|
||
*/
|
||
{
|
||
NDR_PROC_CONTEXT * pContext = & pAsyncMsg->ProcContext;
|
||
if ( pAsyncMsg )
|
||
{
|
||
PMIDL_STUB_MESSAGE pStubMsg = & pAsyncMsg->StubMsg;
|
||
|
||
NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
|
||
|
||
NdrCorrelationFree( pStubMsg );
|
||
|
||
// Free the RPC buffer.
|
||
|
||
if ( pStubMsg->IsClient )
|
||
{
|
||
if ( ! pAsyncMsg->Flags.RuntimeCleanedUp )
|
||
NdrFreeBuffer( pStubMsg );
|
||
}
|
||
|
||
|
||
RPC_STATUS Status = 0;
|
||
|
||
if ( pStubMsg->IsClient )
|
||
{
|
||
if ( pContext->SavedGenericHandle )
|
||
{
|
||
// Note that we cannot unbind after freeing the handle as the stack would be gone.
|
||
|
||
RpcTryExcept
|
||
{
|
||
GenericHandleUnbind( pStubMsg->StubDesc,
|
||
pContext->StartofStack,
|
||
pContext->pHandleFormatSave,
|
||
(pContext->HandleType) ? IMPLICIT_MASK : 0,
|
||
& pContext->SavedGenericHandle );
|
||
}
|
||
RpcExcept(1)
|
||
{
|
||
Status = RpcExceptionCode();
|
||
}
|
||
RpcEndExcept;
|
||
}
|
||
}
|
||
|
||
NdrpAllocaDestroy( &pContext->AllocateContext );
|
||
|
||
// Prevent reusing of a handle that has been freed;
|
||
pAsyncMsg->Signature = NDR_FREED_ASYNC_SIGNATURE;
|
||
|
||
I_RpcBCacheFree( pAsyncMsg );
|
||
|
||
if ( Status )
|
||
RpcRaiseException( Status );
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
NdrpFreeAsyncHandleAndMessage(
|
||
PRPC_ASYNC_STATE AsyncHandle)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Frees an async handle and its associated async message.
|
||
|
||
Arguments:
|
||
AsyncHandle - Supplies the async handle to be freed.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg = (PNDR_ASYNC_MESSAGE)AsyncHandle->StubInfo;
|
||
NdrpFreeAsyncMsg( pAsyncMsg );
|
||
|
||
AsyncHandle->StubInfo = 0;
|
||
AsyncHandle->Signature = RPC_FREED_ASYNC_SIGNATURE;
|
||
I_RpcFree( AsyncHandle );
|
||
}
|
||
|
||
|
||
void
|
||
NdrAsyncSend(
|
||
PMIDL_STUB_MESSAGE pStubMsg,
|
||
BOOL fPartialSend )
|
||
{
|
||
pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
||
|
||
if ( fPartialSend )
|
||
NdrPartialSend( pStubMsg->pContext->pPipeDesc,
|
||
pStubMsg );
|
||
else
|
||
{
|
||
NdrSend( 0, // not used
|
||
pStubMsg,
|
||
FALSE ); // not partial
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
NdrLastAsyncReceive(
|
||
PMIDL_STUB_MESSAGE pStubMsg )
|
||
{
|
||
pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
|
||
|
||
// A complete call.
|
||
// We may have a complete buffer already when pipes are involved.
|
||
|
||
if ( pStubMsg->pContext->pPipeDesc )
|
||
{
|
||
if ( pStubMsg->RpcMsg->RpcFlags & RPC_BUFFER_COMPLETE )
|
||
return;
|
||
|
||
if ( pStubMsg->pContext->pPipeDesc->OutPipes )
|
||
{
|
||
pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_EXTRA;
|
||
}
|
||
else
|
||
{
|
||
pStubMsg->RpcMsg->RpcFlags &= ~RPC_BUFFER_EXTRA;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
NdrReceive( pStubMsg->pContext->pPipeDesc,
|
||
pStubMsg,
|
||
0, // size, ignored for complete calls
|
||
FALSE ); // complete buffer
|
||
}
|
||
|
||
|
||
void
|
||
NdrpRegisterAsyncHandle(
|
||
PMIDL_STUB_MESSAGE pStubMsg,
|
||
void * AsyncHandle )
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
Status = I_RpcAsyncSetHandle( pStubMsg->RpcMsg,
|
||
(RPC_ASYNC_STATE *)AsyncHandle );
|
||
|
||
if ( Status )
|
||
RpcRaiseException( Status );
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NdrpValidateAsyncMsg(
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg )
|
||
{
|
||
if ( ! pAsyncMsg )
|
||
return RPC_S_INVALID_ASYNC_HANDLE;
|
||
|
||
if ( 0 != IsBadWritePtr( pAsyncMsg, sizeof(NDR_ASYNC_MESSAGE)) )
|
||
return RPC_S_INVALID_ASYNC_HANDLE;
|
||
|
||
if ( pAsyncMsg->Signature != NDR_ASYNC_SIGNATURE ||
|
||
pAsyncMsg->Version != NDR_ASYNC_VERSION )
|
||
return RPC_S_INVALID_ASYNC_HANDLE;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NdrpValidateAndLockAsyncHandle(
|
||
IN PRPC_ASYNC_STATE AsyncHandle )
|
||
{
|
||
if ( 0 != IsBadWritePtr( AsyncHandle, sizeof(RPC_ASYNC_STATE)) )
|
||
return RPC_S_INVALID_ASYNC_HANDLE;
|
||
|
||
// Prevent multiple simultanous abort and complete calls.
|
||
|
||
if ( 0 != InterlockedCompareExchange( & AsyncHandle->Lock, 1, 0 ) )
|
||
{
|
||
return RPC_S_INVALID_ASYNC_CALL;
|
||
}
|
||
else
|
||
{
|
||
if ( AsyncHandle->Signature != RPC_ASYNC_SIGNATURE ||
|
||
AsyncHandle->Size != RPC_ASYNC_VERSION_1_0 )
|
||
{
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
return RPC_S_INVALID_ASYNC_HANDLE;
|
||
}
|
||
}
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NdrValidateBothAndLockAsyncHandle(
|
||
IN PRPC_ASYNC_STATE AsyncHandle )
|
||
{
|
||
RPC_STATUS Status = NdrpValidateAndLockAsyncHandle( AsyncHandle );
|
||
|
||
if ( Status != RPC_S_OK )
|
||
return Status;
|
||
|
||
Status = NdrpValidateAsyncMsg( (PNDR_ASYNC_MESSAGE) AsyncHandle->StubInfo );
|
||
|
||
if ( Status != RPC_S_OK )
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
NdrpAsyncAbortCall (
|
||
PRPC_ASYNC_STATE AsyncHandle,
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
unsigned long ExceptionCode,
|
||
BOOL bFreeParams
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Aborts the asynchronous RPC call indicated by AsyncHandle on the server and
|
||
frees memory allocated for the parameters, message, and handle.
|
||
|
||
Arguments:
|
||
AsyncHandle - supplies the async handle for the call
|
||
AsyncMessage - supplies the async message for the call
|
||
ExceptionCode - supplies the exception code to send to the client.
|
||
bFreeParams - TRUE if the parameters should be freed.
|
||
|
||
Return Value:
|
||
NONE.
|
||
|
||
--*/
|
||
{
|
||
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
// If the async call is aborted, see if context handles are fine.
|
||
// We know there is no manager routine exception.
|
||
NdrpCleanupServerContextHandles( &pAsyncMsg->StubMsg,
|
||
pAsyncMsg->ProcContext.StartofStack,
|
||
FALSE );
|
||
|
||
if (bFreeParams)
|
||
{
|
||
NdrpFreeParams( & pAsyncMsg->StubMsg,
|
||
pAsyncMsg->ProcContext.NumberParams, //Number of parameters
|
||
( PPARAM_DESCRIPTION )pAsyncMsg->ProcContext.Params,
|
||
pAsyncMsg->ProcContext.StartofStack );
|
||
}
|
||
|
||
if ( ! pAsyncMsg->Flags.RuntimeCleanedUp )
|
||
Status = I_RpcAsyncAbortCall( AsyncHandle, ExceptionCode);
|
||
|
||
NdrpFreeAsyncHandleAndMessage( AsyncHandle );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
Ndr64pCompleteAsyncClientCall(
|
||
RPC_ASYNC_HANDLE AsyncHandle,
|
||
IN PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
void * pReturnValue
|
||
);
|
||
|
||
RPC_STATUS
|
||
Ndr64pCompleteAsyncServerCall(
|
||
RPC_ASYNC_HANDLE AsyncHandle,
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
void * pReturnValue
|
||
);
|
||
|
||
RPC_STATUS
|
||
Ndr64pAsyncAbortCall(
|
||
PRPC_ASYNC_STATE AsyncHandle,
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
unsigned long ExceptionCode,
|
||
BOOL bFreeParams
|
||
);
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Runtime APIs
|
||
//
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
RpcAsyncInitializeHandle (
|
||
IN PRPC_ASYNC_STATE AsyncHandle,
|
||
IN unsigned int Size
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Initializes an async handle.
|
||
|
||
Arguments:
|
||
AsyncHandle - the async handle directing the call
|
||
|
||
Return Value:
|
||
RPC_S_OK - the call succeeded.
|
||
RPC_S_INVALID_HANDLE - the handle was bad.
|
||
|
||
--*/
|
||
|
||
{
|
||
if ( ! AsyncHandle ||
|
||
Size < RPC_ASYNC_VERSION_1_0 || Size > RPC_ASYNC_CURRENT_VERSION )
|
||
return RPC_S_INVALID_ARG;
|
||
|
||
if ( 0 != IsBadWritePtr( AsyncHandle, sizeof(RPC_ASYNC_STATE)) )
|
||
return RPC_S_INVALID_ASYNC_HANDLE;
|
||
|
||
AsyncHandle->Size = RPC_ASYNC_CURRENT_VERSION;
|
||
AsyncHandle->Signature = RPC_ASYNC_SIGNATURE;
|
||
AsyncHandle->Flags = 0;
|
||
AsyncHandle->Lock = 0;
|
||
AsyncHandle->StubInfo = 0;
|
||
AsyncHandle->RuntimeInfo = 0;
|
||
AsyncHandle->Reserved[0] = 0;
|
||
AsyncHandle->Reserved[1] = 0;
|
||
AsyncHandle->Reserved[2] = 0;
|
||
AsyncHandle->Reserved[3] = 0;
|
||
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
RpcAsyncAbortCall (
|
||
IN PRPC_ASYNC_STATE AsyncHandle,
|
||
IN unsigned long ExceptionCode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This API is valid only on the server side and is a request to abort
|
||
the call. The asynchronous handle is deleted and no additional API calls
|
||
on that handle are permitted.
|
||
|
||
Note that RpcCancelAsyncCall is a different API that is used on the client
|
||
side only.
|
||
|
||
Arguments:
|
||
AsyncHandle - the async handle directing the call
|
||
|
||
Return Value:
|
||
RPC_S_OK - the call succeeded.
|
||
RPC_S_INVALID_HANDLE - the handle was bad.
|
||
RPC_S_INVALID_ASYNC_CALL - May not be called on the client.
|
||
Other errors from the RPC runtime layer.
|
||
|
||
Note: This API cannot be called on the client side.
|
||
|
||
--*/
|
||
|
||
{
|
||
RPC_STATUS Status;
|
||
PNDR_ASYNC_MESSAGE pAsyncMsg;
|
||
|
||
Status = NdrValidateBothAndLockAsyncHandle( AsyncHandle );
|
||
if (RPC_S_OK != Status)
|
||
{
|
||
return Status;
|
||
}
|
||
|
||
pAsyncMsg = (PNDR_ASYNC_MESSAGE)AsyncHandle->StubInfo;
|
||
if ( pAsyncMsg->StubMsg.IsClient )
|
||
{
|
||
// Abort is not valid on the client.
|
||
InterlockedDecrement( & AsyncHandle->Lock );
|
||
return RPC_S_INVALID_ASYNC_CALL;
|
||
}
|
||
|
||
#if defined(BUILD_NDR64)
|
||
if ( pAsyncMsg->ProcContext.CurrentSyntaxType == XFER_SYNTAX_DCE )
|
||
return NdrpAsyncAbortCall( AsyncHandle,
|
||
pAsyncMsg,
|
||
ExceptionCode,
|
||
TRUE ); // Free parameters
|
||
else
|
||
return Ndr64pAsyncAbortCall( AsyncHandle,
|
||
pAsyncMsg,
|
||
ExceptionCode,
|
||
TRUE ); // Free parameters
|
||
#else
|
||
|
||
return NdrpAsyncAbortCall( AsyncHandle,
|
||
pAsyncMsg,
|
||
ExceptionCode,
|
||
TRUE ); // Free parameters
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
RPC_STATUS
|
||
Ndr64pCompleteAsyncCall (
|
||
IN PRPC_ASYNC_STATE AsyncHandle,
|
||
IN PNDR_ASYNC_MESSAGE pAsyncMsg,
|
||
IN void * pReply
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completes the virtual async call on server or client side.
|
||
|
||
Arguments:
|
||
|
||
AsyncHandle - the async handle controlling the call
|
||
Reply - return value:
|
||
on server - passed in
|
||
on client - returned out
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Function succeeded
|
||
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status;
|
||
|
||
RpcTryExcept
|
||
{
|
||
if ( pAsyncMsg->StubMsg.IsClient )
|
||
{
|
||
#if defined(BUILD_NDR64)
|
||
if ( pAsyncMsg->ProcContext.CurrentSyntaxType == XFER_SYNTAX_DCE )
|
||
Status = NdrpCompleteAsyncClientCall( AsyncHandle, pAsyncMsg, pReply );
|
||
else
|
||
Status = Ndr64pCompleteAsyncClientCall( AsyncHandle, pAsyncMsg, pReply );
|
||
#else
|
||
NDR_ASSERT( pAsyncMsg->ProcContext.CurrentSyntaxType == XFER_SYNTAX_DCE,
|
||
"Invalid transfer syntax" );
|
||
Status = NdrpCompleteAsyncClientCall( AsyncHandle, pAsyncMsg, pReply );
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
#if defined(BUILD_NDR64)
|
||
if ( pAsyncMsg->ProcContext.CurrentSyntaxType == XFER_SYNTAX_DCE )
|
||
Status = NdrpCompleteAsyncServerCall ( AsyncHandle, pAsyncMsg, pReply );
|
||
else
|
||
Status = Ndr64pCompleteAsyncServerCall( AsyncHandle, pAsyncMsg, pReply );
|
||
#else
|
||
NDR_ASSERT( pAsyncMsg->ProcContext.CurrentSyntaxType == XFER_SYNTAX_DCE,
|
||
"Invalid transfer Syntax" );
|
||
Status = NdrpCompleteAsyncServerCall ( AsyncHandle, pAsyncMsg, pReply );
|
||
#endif
|
||
}
|
||
}
|
||
RpcExcept( !(RPC_BAD_STUB_DATA_EXCEPTION_FILTER) )
|
||
{
|
||
Status = RpcExceptionCode();
|
||
}
|
||
RpcEndExcept
|
||
|
||
return Status;
|
||
}
|
||
|
||
RPC_STATUS RPC_ENTRY
|
||
RpcAsyncCompleteCall (
|
||
IN PRPC_ASYNC_STATE AsyncHandle,
|
||
IN void * pReply
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completes the virtual async call on server or client side.
|
||
|
||
Arguments:
|
||
|
||
AsyncHandle - the async handle controlling the call
|
||
Reply - return value:
|
||
on server - passed in
|
||
on client - returned out
|
||
|
||
Return Value:
|
||
|
||
RPC_S_OK - Function succeeded
|
||
RPC_S_OUT_OF_MEMORY - we ran out of memory
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = NdrValidateBothAndLockAsyncHandle( AsyncHandle );
|
||
|
||
if ( Status == RPC_S_OK )
|
||
{
|
||
Status = Ndr64pCompleteAsyncCall( AsyncHandle,
|
||
(PNDR_ASYNC_MESSAGE) AsyncHandle->StubInfo,
|
||
pReply );
|
||
}
|
||
|
||
return Status;
|
||
}
|