[PATCH 1/2] rpcrt4: Implement NdrAsyncServerCall.

Dmitry Timoshkov dmitry at baikal.ru
Fri Sep 13 00:34:33 CDT 2019


Based on NdrStubCall2 and NdrAsyncClientCall implementations.

In order to test asynchronous RPC I used dlls/rpcrt4/tests/server.c as a base,
converted int_return() and sum() to use asynchronous RPC on both client and
server sides (server.idl doesn't need any changes), and added server.acf:
interface IServer
{
    [async] int_return();
    [async] sum();
}
With this implementation these tests pass under Wine. Since widl doesn't
support asynchronous RPC it's impossible to add appropriate Wine tests.

Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/rpcrt4/ndr_stubless.c | 190 +++++++++++++++++++++++++++++++++----
 dlls/rpcrt4/ndr_stubless.h |  15 +++
 dlls/rpcrt4/rpc_async.c    |  11 ++-
 3 files changed, 199 insertions(+), 17 deletions(-)

diff --git a/dlls/rpcrt4/ndr_stubless.c b/dlls/rpcrt4/ndr_stubless.c
index 90537515ea..70a26dd5b3 100644
--- a/dlls/rpcrt4/ndr_stubless.c
+++ b/dlls/rpcrt4/ndr_stubless.c
@@ -1559,21 +1559,6 @@ void WINAPI NdrServerCallAll( PRPC_MESSAGE msg )
     FIXME("%p stub\n", msg);
 }
 
-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 int number_of_params;
-    /* correlation cache */
-    ULONG_PTR NdrCorrCache[256];
-};
-
 /* Helper for ndr_async_client_call, to factor out the part that may or may not be
  * guarded by a try/except block. */
 static void do_ndr_async_client_call( const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormat, void **stack_top )
@@ -1922,5 +1907,178 @@ RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
 
 void RPC_ENTRY NdrAsyncServerCall(PRPC_MESSAGE pRpcMsg)
 {
-    FIXME("unimplemented, %p\n", pRpcMsg);
+    const MIDL_SERVER_INFO *pServerInfo;
+    const MIDL_STUB_DESC *pStubDesc;
+    PFORMAT_STRING pFormat;
+    /* pointer to start of stack to pass into stub implementation */
+    unsigned char *args;
+    /* header for procedure string */
+    const NDR_PROC_HEADER *pProcHeader;
+    struct async_call_data *async_call_data;
+    PRPC_ASYNC_STATE pAsync;
+    RPC_STATUS status;
+
+    TRACE("%p\n", pRpcMsg);
+
+    pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
+
+    pStubDesc = pServerInfo->pStubDesc;
+    pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
+    pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
+
+    TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
+
+    async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
+    if (!async_call_data) RpcRaiseException(RPC_X_NO_MEMORY);
+    async_call_data->pProcHeader = pProcHeader;
+
+    async_call_data->pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
+    *(PRPC_MESSAGE)(async_call_data->pStubMsg + 1) = *pRpcMsg;
+
+    if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
+    {
+        const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
+        async_call_data->stack_size = header_rpc->stack_size;
+        pFormat += sizeof(NDR_PROC_HEADER_RPC);
+    }
+    else
+    {
+        async_call_data->stack_size = pProcHeader->stack_size;
+        pFormat += sizeof(NDR_PROC_HEADER);
+    }
+
+    TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
+
+    /* binding */
+    switch (pProcHeader->handle_type)
+    {
+    /* explicit binding: parse additional section */
+    case 0:
+        switch (*pFormat) /* handle_type */
+        {
+        case FC_BIND_PRIMITIVE: /* explicit primitive */
+            pFormat += sizeof(NDR_EHD_PRIMITIVE);
+            break;
+        case FC_BIND_GENERIC: /* explicit generic */
+            pFormat += sizeof(NDR_EHD_GENERIC);
+            break;
+        case FC_BIND_CONTEXT: /* explicit context */
+            pFormat += sizeof(NDR_EHD_CONTEXT);
+            break;
+        default:
+            ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+            RpcRaiseException(RPC_X_BAD_STUB_DATA);
+        }
+        break;
+    case FC_BIND_GENERIC: /* implicit generic */
+    case FC_BIND_PRIMITIVE: /* implicit primitive */
+    case FC_CALLBACK_HANDLE: /* implicit callback */
+    case FC_AUTO_HANDLE: /* implicit auto handle */
+        break;
+    default:
+        ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
+        RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    }
+
+    if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
+    {
+        ERR("objects not supported\n");
+        I_RpcFree(async_call_data);
+        RpcRaiseException(RPC_X_BAD_STUB_DATA);
+    }
+
+    NdrServerInitializeNew(pRpcMsg, async_call_data->pStubMsg, pStubDesc);
+
+    /* create the full pointer translation tables, if requested */
+    if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
+        async_call_data->pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0, XLAT_SERVER);
+
+    /* use alternate memory allocation routines */
+    if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
+#if 0
+          NdrRpcSsEnableAllocate(&stubMsg);
+#else
+          FIXME("Set RPCSS memory allocation routines\n");
+#endif
+
+    TRACE("allocating memory for stack of size %x\n", async_call_data->stack_size);
+
+    args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, async_call_data->stack_size);
+    async_call_data->pStubMsg->StackTop = args; /* used by conformance of top-level objects */
+
+    pAsync = I_RpcAllocate(sizeof(*pAsync));
+    if (!pAsync) RpcRaiseException(RPC_X_NO_MEMORY);
+
+    status = RpcAsyncInitializeHandle(pAsync, sizeof(*pAsync));
+    if (status != RPC_S_OK)
+        RpcRaiseException(status);
+
+    pAsync->StubInfo = async_call_data;
+    TRACE("pAsync %p, pAsync->StubInfo %p, pFormat %p\n", pAsync, pAsync->StubInfo, async_call_data->pHandleFormat);
+
+    /* add the implicit pAsync pointer as the first arg to the function */
+    *(void **)args = pAsync;
+
+    if (is_oicf_stubdesc(pStubDesc))
+    {
+        const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
+        /* cache of Oif_flags from v2 procedure header */
+        INTERPRETER_OPT_FLAGS Oif_flags;
+        /* cache of extension flags from NDR_PROC_HEADER_EXTS */
+        INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
+
+        Oif_flags = pOIFHeader->Oi2Flags;
+        async_call_data->number_of_params = pOIFHeader->number_of_params;
+
+        pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
+
+        TRACE("Oif_flags = %s\n", debugstr_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;
+        }
+
+        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(async_call_data->pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
+            if (ext_flags.Unused & 0x2) /* has range on conformance */
+                async_call_data->pStubMsg->CorrDespIncrement = 12;
+        }
+    }
+    else
+    {
+        pFormat = convert_old_args( async_call_data->pStubMsg, pFormat, async_call_data->stack_size,
+                                    pProcHeader->Oi_flags & Oi_OBJECT_PROC,
+                                    /* reuse the correlation cache, it's not needed for v1 format */
+                                    async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), &async_call_data->number_of_params );
+    }
+
+    /* convert strings, floating point values and endianness into our
+     * preferred format */
+    if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
+        NdrConvert(async_call_data->pStubMsg, pFormat);
+
+    async_call_data->pHandleFormat = pFormat;
+
+    /* 1. UNMARSHAL */
+    TRACE("UNMARSHAL\n");
+    stub_do_args(async_call_data->pStubMsg, pFormat, STUBLESS_UNMARSHAL, async_call_data->number_of_params);
+
+    /* 2. CALLSERVER */
+    TRACE("CALLSERVER\n");
+    if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
+        pServerInfo->ThunkTable[pRpcMsg->ProcNum](async_call_data->pStubMsg);
+    else
+        call_server_func(pServerInfo->DispatchTable[pRpcMsg->ProcNum], args, async_call_data->stack_size);
 }
diff --git a/dlls/rpcrt4/ndr_stubless.h b/dlls/rpcrt4/ndr_stubless.h
index 606513ff24..fc67cf9020 100644
--- a/dlls/rpcrt4/ndr_stubless.h
+++ b/dlls/rpcrt4/ndr_stubless.h
@@ -224,6 +224,21 @@ typedef struct _NDR_EHD_CONTEXT
 
 #include "poppack.h"
 
+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 int number_of_params;
+    /* correlation cache */
+    ULONG_PTR NdrCorrCache[256];
+};
+
 enum stubless_phase
 {
     STUBLESS_UNMARSHAL,
diff --git a/dlls/rpcrt4/rpc_async.c b/dlls/rpcrt4/rpc_async.c
index 891fc5ad72..9c3d90cfba 100644
--- a/dlls/rpcrt4/rpc_async.c
+++ b/dlls/rpcrt4/rpc_async.c
@@ -110,6 +110,8 @@ RPC_STATUS WINAPI RpcAsyncGetCallStatus(PRPC_ASYNC_STATE pAsync)
  */
 RPC_STATUS WINAPI RpcAsyncCompleteCall(PRPC_ASYNC_STATE pAsync, void *Reply)
 {
+    struct async_call_data *data;
+
     TRACE("(%p, %p)\n", pAsync, Reply);
 
     if (!valid_async_handle(pAsync))
@@ -117,7 +119,14 @@ RPC_STATUS WINAPI RpcAsyncCompleteCall(PRPC_ASYNC_STATE pAsync, void *Reply)
 
     /* FIXME: check completed */
 
-    return NdrpCompleteAsyncClientCall(pAsync, Reply);
+    TRACE("pAsync %p, pAsync->StubInfo %p\n", pAsync, pAsync->StubInfo);
+
+    data = pAsync->StubInfo;
+    if (data->pStubMsg->IsClient)
+        return NdrpCompleteAsyncClientCall(pAsync, Reply);
+
+    FIXME("not implemented for server side\n");
+    return RPC_S_CALL_FAILED;
 }
 
 /***********************************************************************
-- 
2.20.1




More information about the wine-devel mailing list