rpcrt4: Implement stubless asynchronous NDR interpreter.

CodeWeavers did this work for supporting Outlook 2007.
This commit is contained in:
Rob Shearman 2009-03-18 10:59:35 +00:00 committed by Alexandre Julliard
parent 9c6e6efa32
commit 834c5b4275
5 changed files with 354 additions and 3 deletions

View File

@ -1522,3 +1522,339 @@ void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
DWORD dwPhase;
NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
}
struct async_call_data
{
MIDL_STUB_MESSAGE *pStubMsg;
const NDR_PROC_HEADER *pProcHeader;
PFORMAT_STRING pHandleFormat;
PFORMAT_STRING pParamFormat;
RPC_BINDING_HANDLE hBinding;
/* size of stack */
unsigned short stack_size;
/* number of parameters. optional for client to give it to us */
unsigned char number_of_params;
/* correlation cache */
unsigned long NdrCorrCache[256];
};
LONG_PTR WINAPIV NdrAsyncClientCall(PMIDL_STUB_DESC pStubDesc,
PFORMAT_STRING pFormat, ...)
{
/* pointer to start of stack where arguments start */
PRPC_MESSAGE pRpcMsg;
PMIDL_STUB_MESSAGE pStubMsg;
RPC_ASYNC_STATE *pAsync;
struct async_call_data *async_call_data;
/* procedure number */
unsigned short procedure_number;
/* cache of Oif_flags from v2 procedure header */
INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
/* cache of extension flags from NDR_PROC_HEADER_EXTS */
INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
/* the type of pass we are currently doing */
int phase;
/* header for procedure string */
const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
/* -Oif or -Oicf generated format */
BOOL bV2Format = FALSE;
TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
/* Later NDR language versions probably won't be backwards compatible */
if (pStubDesc->Version > 0x50002)
{
FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
}
async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
if (!async_call_data) RpcRaiseException(ERROR_OUTOFMEMORY);
async_call_data->number_of_params = ~0;
async_call_data->pProcHeader = pProcHeader;
async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1);
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
{
const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
async_call_data->stack_size = pProcHeader->stack_size;
procedure_number = pProcHeader->proc_num;
pFormat += sizeof(NDR_PROC_HEADER_RPC);
}
else
{
async_call_data->stack_size = pProcHeader->stack_size;
procedure_number = pProcHeader->proc_num;
pFormat += sizeof(NDR_PROC_HEADER);
}
TRACE("stack size: 0x%x\n", async_call_data->stack_size);
TRACE("proc num: %d\n", procedure_number);
/* create the full pointer translation tables, if requested */
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)
{
ERR("objects not supported\n");
I_RpcFree(async_call_data);
RpcRaiseException(RPC_X_BAD_STUB_DATA);
}
NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number);
TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
/* needed for conformance of top-level objects */
#ifdef __i386__
pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size);
/* FIXME: this may read one more DWORD than is necessary, but it shouldn't hurt */
memcpy(pStubMsg->StackTop, *(unsigned char **)(&pFormat+1), async_call_data->stack_size);
#else
# warning Stack not retrieved for your CPU architecture
#endif
pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop;
pAsync->StubInfo = async_call_data;
async_call_data->pHandleFormat = pFormat;
pFormat = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, &async_call_data->hBinding);
if (!pFormat) return 0;
bV2Format = (pStubDesc->Version >= 0x20000);
if (bV2Format)
{
const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
(const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
Oif_flags = pOIFHeader->Oi2Flags;
async_call_data->number_of_params = pOIFHeader->number_of_params;
pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
}
TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags);
if (Oif_flags.HasExtensions)
{
const NDR_PROC_HEADER_EXTS *pExtensions =
(const NDR_PROC_HEADER_EXTS *)pFormat;
ext_flags = pExtensions->Flags2;
pFormat += pExtensions->Size;
}
async_call_data->pParamFormat = pFormat;
pStubMsg->BufferLength = 0;
/* store the RPC flags away */
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS)
pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
/* use alternate memory allocation routines */
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC)
NdrRpcSmSetClientToOsf(pStubMsg);
if (Oif_flags.HasPipes)
{
FIXME("pipes not supported yet\n");
RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
/* init pipes package */
/* NdrPipesInitialize(...) */
}
if (ext_flags.HasNewCorrDesc)
{
/* initialize extra correlation package */
NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
}
/* order of phases:
* 1. PROXY_CALCSIZE - calculate the buffer size
* 2. PROXY_GETBUFFER - allocate the buffer
* 3. PROXY_MARHSAL - marshal [in] params into the buffer
* 4. PROXY_SENDRECEIVE - send buffer
* Then in NdrpCompleteAsyncClientCall:
* 1. PROXY_SENDRECEIVE - receive buffer
* 2. PROXY_UNMARHSAL - unmarshal [out] params from buffer
*/
for (phase = PROXY_CALCSIZE; phase <= PROXY_SENDRECEIVE; phase++)
{
RPC_STATUS status;
TRACE("phase = %d\n", phase);
switch (phase)
{
case PROXY_GETBUFFER:
/* allocate the buffer */
if (Oif_flags.HasPipes)
/* NdrGetPipeBuffer(...) */
FIXME("pipes not supported yet\n");
else
{
if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
#if 0
NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
#else
FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
#endif
else
NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
}
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
status = I_RpcAsyncSetHandle(pRpcMsg, pAsync);
if (status != RPC_S_OK)
RpcRaiseException(status);
break;
case PROXY_SENDRECEIVE:
pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
/* send the [in] params only */
if (Oif_flags.HasPipes)
/* NdrPipesSend(...) */
FIXME("pipes not supported yet\n");
else
{
if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
#if 0
NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
#else
FIXME("using auto handle - call NdrNsSend when it gets implemented\n");
#endif
else
{
pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
status = I_RpcSend(pStubMsg->RpcMsg);
if (status != RPC_S_OK)
RpcRaiseException(status);
}
}
break;
case PROXY_CALCSIZE:
case PROXY_MARSHAL:
if (bV2Format)
client_do_args(pStubMsg, pFormat, phase, pStubMsg->StackTop,
async_call_data->number_of_params, NULL);
else
client_do_args_old_format(pStubMsg, pFormat, phase,
pStubMsg->StackTop, async_call_data->stack_size, NULL,
(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT), FALSE);
break;
default:
ERR("shouldn't reach here. phase %d\n", phase);
break;
}
}
TRACE("returning 0\n");
return 0;
}
RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply)
{
/* pointer to start of stack where arguments start */
PMIDL_STUB_MESSAGE pStubMsg;
struct async_call_data *async_call_data;
/* the type of pass we are currently doing */
int phase;
/* header for procedure string */
const NDR_PROC_HEADER * pProcHeader;
/* -Oif or -Oicf generated format */
BOOL bV2Format;
RPC_STATUS status = RPC_S_OK;
if (!pAsync->StubInfo)
return RPC_S_INVALID_ASYNC_HANDLE;
async_call_data = pAsync->StubInfo;
pStubMsg = async_call_data->pStubMsg;
pProcHeader = async_call_data->pProcHeader;
bV2Format = (pStubMsg->StubDesc->Version >= 0x20000);
/* order of phases:
* 1. PROXY_CALCSIZE - calculate the buffer size
* 2. PROXY_GETBUFFER - allocate the buffer
* 3. PROXY_MARHSAL - marshal [in] params into the buffer
* 4. PROXY_SENDRECEIVE - send buffer
* Then in NdrpCompleteAsyncClientCall:
* 1. PROXY_SENDRECEIVE - receive buffer
* 2. PROXY_UNMARHSAL - unmarshal [out] params from buffer
*/
for (phase = PROXY_SENDRECEIVE; phase <= PROXY_UNMARSHAL; phase++)
{
switch (phase)
{
case PROXY_SENDRECEIVE:
pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
/* receive the [out] params */
if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE)
#if 0
NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
#else
FIXME("using auto handle - call NdrNsReceive when it gets implemented\n");
#endif
else
{
status = I_RpcReceive(pStubMsg->RpcMsg);
if (status != RPC_S_OK)
goto cleanup;
pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
pStubMsg->Buffer = pStubMsg->BufferStart;
}
/* convert strings, floating point values and endianess into our
* preferred format */
#if 0
if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
NdrConvert(pStubMsg, pFormat);
#endif
break;
case PROXY_UNMARSHAL:
if (bV2Format)
client_do_args(pStubMsg, async_call_data->pParamFormat, phase, pStubMsg->StackTop,
async_call_data->number_of_params, Reply);
else
client_do_args_old_format(pStubMsg, async_call_data->pParamFormat, phase,
pStubMsg->StackTop, async_call_data->stack_size, Reply, FALSE, FALSE);
break;
default:
ERR("shouldn't reach here. phase %d\n", phase);
break;
}
}
cleanup:
if (pStubMsg->fHasNewCorrDesc)
{
/* free extra correlation package */
NdrCorrelationFree(pStubMsg);
}
/* free the full pointer translation tables */
if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR)
NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
/* free marshalling buffer */
NdrFreeBuffer(pStubMsg);
client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding);
I_RpcFree(pStubMsg->StackTop);
I_RpcFree(async_call_data);
TRACE("-- 0x%x\n", status);
return status;
}
RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg,
DWORD * pdwStubPhase)
{
FIXME("unimplemented, expect crash!\n");
return 0;
}

View File

@ -240,3 +240,4 @@ void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg,
PFORMAT_STRING pFormat, int phase, unsigned char *args,
unsigned short stack_size, unsigned char *pRetVal, BOOL object_proc,
BOOL ignore_retval);
RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply);

View File

@ -416,6 +416,7 @@ RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc,
void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
{
assert(!Connection->server);
Connection->async_state = NULL;
EnterCriticalSection(&assoc->cs);
if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id;
list_add_head(&assoc->free_connection_pool, &Connection->conn_pool_entry);

View File

@ -29,11 +29,17 @@
#include "rpc_binding.h"
#include "rpc_message.h"
#include "ndr_stubless.h"
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
#define RPC_ASYNC_SIGNATURE 0x43595341
static inline BOOL valid_async_handle(PRPC_ASYNC_STATE pAsync)
{
return pAsync->Signature == RPC_ASYNC_SIGNATURE;
}
/***********************************************************************
* RpcAsyncInitializeHandle [RPCRT4.@]
*
@ -104,8 +110,14 @@ RPC_STATUS WINAPI RpcAsyncGetCallStatus(PRPC_ASYNC_STATE pAsync)
*/
RPC_STATUS WINAPI RpcAsyncCompleteCall(PRPC_ASYNC_STATE pAsync, void *Reply)
{
FIXME("(%p, %p): stub\n", pAsync, Reply);
TRACE("(%p, %p)\n", pAsync, Reply);
if (!valid_async_handle(pAsync))
return RPC_S_INVALID_ASYNC_HANDLE;
/* FIXME: check completed */
return NdrpCompleteAsyncClientCall(pAsync, Reply);
}
/***********************************************************************

View File

@ -116,8 +116,9 @@
@ stdcall NDRSContextUnmarshallEx(ptr ptr ptr)
@ stub NDRcopy
@ stdcall NdrAllocate(ptr long)
@ stub NdrAsyncClientCall
@ varargs NdrAsyncClientCall(ptr ptr)
@ stub NdrAsyncServerCall
@ stdcall NdrAsyncStubCall(ptr ptr ptr ptr)
@ stdcall NdrByteCountPointerBufferSize(ptr ptr ptr)
@ stdcall NdrByteCountPointerFree(ptr ptr ptr)
@ stdcall NdrByteCountPointerMarshall(ptr ptr ptr)