- Update rpcrt4 to Wine-20080105, so it corresponds to the WIDL. Local changes applied.

svn path=/trunk/; revision=31631
This commit is contained in:
Aleksey Bragin 2008-01-06 16:18:31 +00:00
parent 07dce281aa
commit ecdee48d72
26 changed files with 12518 additions and 11057 deletions

View file

@ -41,7 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
static WINE_EXCEPTION_FILTER(stub_filter)
{
if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
if (GetExceptionInformation()->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
return EXCEPTION_CONTINUE_SEARCH;
return EXCEPTION_EXECUTE_HANDLER;
}
@ -109,13 +109,15 @@ static CRITICAL_SECTION delegating_vtbl_section = { &critsect_debug, -1, 0, 0, 0
typedef struct
{
DWORD ref;
DWORD size;
void **methods;
IUnknownVtbl vtbl;
/* remaining entries in vtbl */
} ref_counted_vtbl;
static struct
{
ref_counted_vtbl *table;
DWORD size;
} current_vtbl;
@ -156,7 +158,7 @@ typedef struct {
} vtbl_method_t;
#include "poppack.h"
static void fill_table(IUnknownVtbl *vtbl, DWORD num)
static void fill_table(IUnknownVtbl *vtbl, void **methods, DWORD num)
{
vtbl_method_t *method;
void **entry;
@ -166,7 +168,7 @@ static void fill_table(IUnknownVtbl *vtbl, DWORD num)
vtbl->AddRef = delegating_AddRef;
vtbl->Release = delegating_Release;
method = (vtbl_method_t*)((void **)vtbl + num);
method = (vtbl_method_t*)methods;
entry = (void**)(vtbl + 1);
for(i = 3; i < num; i++)
@ -209,19 +211,25 @@ void create_delegating_vtbl(DWORD num_methods)
}
EnterCriticalSection(&delegating_vtbl_section);
if(num_methods > current_vtbl.size)
if(!current_vtbl.table || num_methods > current_vtbl.table->size)
{
DWORD size;
DWORD old_protect;
if(current_vtbl.table && current_vtbl.table->ref == 0)
{
TRACE("freeing old table\n");
VirtualFree(current_vtbl.table->methods,
(current_vtbl.table->size - 3) * sizeof(vtbl_method_t),
MEM_RELEASE);
HeapFree(GetProcessHeap(), 0, current_vtbl.table);
}
size = sizeof(DWORD) + num_methods * sizeof(void*) + (num_methods - 3) * sizeof(vtbl_method_t);
current_vtbl.table = HeapAlloc(GetProcessHeap(), 0, size);
fill_table(&current_vtbl.table->vtbl, num_methods);
size = (num_methods - 3) * sizeof(vtbl_method_t);
current_vtbl.table = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(ref_counted_vtbl, vtbl) + num_methods * sizeof(void*));
current_vtbl.table->ref = 0;
current_vtbl.size = num_methods;
current_vtbl.table->size = num_methods;
current_vtbl.table->methods = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
fill_table(&current_vtbl.table->vtbl, current_vtbl.table->methods, num_methods);
VirtualProtect(current_vtbl.table->methods, size, PAGE_EXECUTE_READ, &old_protect);
}
LeaveCriticalSection(&delegating_vtbl_section);
}
@ -247,6 +255,9 @@ static void release_delegating_vtbl(IUnknownVtbl *vtbl)
if(table->ref == 0 && table != current_vtbl.table)
{
TRACE("... and we're not current so free'ing\n");
VirtualFree(current_vtbl.table->methods,
(current_vtbl.table->size - 3) * sizeof(vtbl_method_t),
MEM_RELEASE);
HeapFree(GetProcessHeap(), 0, table);
}
LeaveCriticalSection(&delegating_vtbl_section);
@ -558,6 +569,9 @@ void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg,
TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer);
NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor);
pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer;
IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer,
&pStubMsg->dwDestContext,
&pStubMsg->pvDestContext);
}
/***********************************************************************
@ -581,7 +595,5 @@ void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER iface,
return;
}
pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
pStubMsg->Buffer = pStubMsg->BufferStart;
pStubMsg->Buffer = pStubMsg->RpcMsg->Buffer;
}

View file

@ -53,8 +53,6 @@ void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE
TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n",
pRpcMessage, pStubMsg, pStubDesc, ProcNum);
assert( pRpcMessage && pStubMsg && pStubDesc );
pRpcMessage->Handle = NULL;
pRpcMessage->ProcNum = ProcNum;
pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation;
@ -106,22 +104,42 @@ unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_M
{
TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc);
assert( pRpcMsg && pStubMsg && pStubDesc );
/* not everyone allocates stack space for w2kReserved */
memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo));
pStubMsg->ReuseBuffer = TRUE;
pStubMsg->IsClient = FALSE;
pStubMsg->StubDesc = pStubDesc;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
pStubMsg->RpcMsg = pRpcMsg;
pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer;
pStubMsg->BufferEnd = pStubMsg->Buffer + pRpcMsg->BufferLength;
pStubMsg->BufferLength = pRpcMsg->BufferLength;
pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength;
pStubMsg->IsClient = FALSE;
pStubMsg->ReuseBuffer = FALSE;
pStubMsg->pAllocAllNodesContext = NULL;
pStubMsg->pPointerQueueState = NULL;
pStubMsg->IgnoreEmbeddedPointers = 0;
pStubMsg->PointerBufferMark = NULL;
pStubMsg->uFlags = 0;
pStubMsg->pfnAllocate = pStubDesc->pfnAllocate;
pStubMsg->pfnFree = pStubDesc->pfnFree;
pStubMsg->StackTop = NULL;
pStubMsg->StubDesc = pStubDesc;
pStubMsg->FullPtrXlatTables = NULL;
pStubMsg->FullPtrRefId = 0;
pStubMsg->PointerLength = 0;
pStubMsg->fInDontFree = 0;
pStubMsg->fDontCallFreeInst = 0;
pStubMsg->fInOnlyParam = 0;
pStubMsg->fHasReturn = 0;
pStubMsg->fHasExtensions = 0;
pStubMsg->fHasNewCorrDesc = 0;
pStubMsg->fUnused = 0;
pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE;
pStubMsg->pvDestContext = NULL;
pStubMsg->pRpcChannelBuffer = NULL;
pStubMsg->pArrayInfo = NULL;
pStubMsg->dwStubPhase = 0;
/* FIXME: LowStackMark */
pStubMsg->pAsyncMsg = NULL;
pStubMsg->pCorrInfo = NULL;
pStubMsg->pCorrMemory = NULL;
pStubMsg->pMemoryList = NULL;
/* FIXME: determine the proper return value */
return NULL;
}
@ -130,31 +148,33 @@ unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_M
*/
unsigned char *WINAPI NdrGetBuffer(PMIDL_STUB_MESSAGE stubmsg, ULONG buflen, RPC_BINDING_HANDLE handle)
{
TRACE("(stubmsg == ^%p, buflen == %u, handle == %p): wild guess.\n", stubmsg, buflen, handle);
RPC_STATUS status;
assert( stubmsg && stubmsg->RpcMsg );
TRACE("(stubmsg == ^%p, buflen == %u, handle == %p)\n", stubmsg, buflen, handle);
/* I guess this is our chance to put the binding handle into the RPC_MESSAGE */
stubmsg->RpcMsg->Handle = handle;
stubmsg->RpcMsg->BufferLength = buflen;
if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK)
return NULL;
stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer;
status = I_RpcGetBuffer(stubmsg->RpcMsg);
if (status != RPC_S_OK)
RpcRaiseException(status);
stubmsg->Buffer = stubmsg->RpcMsg->Buffer;
stubmsg->fBufferValid = TRUE;
stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength;
stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength;
return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer);
return stubmsg->Buffer;
}
/***********************************************************************
* NdrFreeBuffer [RPCRT4.@]
*/
void WINAPI NdrFreeBuffer(PMIDL_STUB_MESSAGE pStubMsg)
{
TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg);
TRACE("(pStubMsg == ^%p)\n", pStubMsg);
if (pStubMsg->fBufferValid)
{
I_RpcFreeBuffer(pStubMsg->RpcMsg);
pStubMsg->BufferLength = 0;
pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL);
pStubMsg->fBufferValid = FALSE;
}
}
/************************************************************************

View file

@ -0,0 +1,345 @@
/*
* NDR data marshalling
*
* Copyright 2006 Mike McCormack (for CodeWeavers)
* Copyright 2006-2007 Robert Shearman (for CodeWeavers)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "ndr_misc.h"
#include "rpc_assoc.h"
#include "rpcndr.h"
#include "wine/rpcfc.h"
#include "wine/debug.h"
#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
#define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
typedef struct ndr_context_handle
{
ULONG attributes;
GUID uuid;
} ndr_context_handle;
struct context_handle_entry
{
struct list entry;
DWORD magic;
RPC_BINDING_HANDLE handle;
ndr_context_handle wire_data;
};
static struct list context_handle_list = LIST_INIT(context_handle_list);
static CRITICAL_SECTION ndr_context_cs;
static CRITICAL_SECTION_DEBUG ndr_context_debug =
{
0, 0, &ndr_context_cs,
{ &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
};
static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
{
struct context_handle_entry *che = (struct context_handle_entry*) CContext;
if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
return NULL;
return che;
}
static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
{
struct context_handle_entry *che;
LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
if (IsEqualGUID(&che->wire_data.uuid, uuid))
return che;
return NULL;
}
RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
{
struct context_handle_entry *che;
RPC_BINDING_HANDLE handle = NULL;
TRACE("%p\n", CContext);
EnterCriticalSection(&ndr_context_cs);
che = get_context_entry(CContext);
if (che)
handle = che->handle;
LeaveCriticalSection(&ndr_context_cs);
if (!handle)
RpcRaiseException(ERROR_INVALID_HANDLE);
return handle;
}
void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
{
struct context_handle_entry *che;
TRACE("%p %p\n", CContext, pBuff);
if (CContext)
{
EnterCriticalSection(&ndr_context_cs);
che = get_context_entry(CContext);
memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
LeaveCriticalSection(&ndr_context_cs);
}
else
{
ndr_context_handle *wire_data = (ndr_context_handle *)pBuff;
wire_data->attributes = 0;
wire_data->uuid = GUID_NULL;
}
}
/***********************************************************************
* RpcSmDestroyClientContext [RPCRT4.@]
*/
RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
{
RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
struct context_handle_entry *che = NULL;
TRACE("(%p)\n", ContextHandle);
EnterCriticalSection(&ndr_context_cs);
che = get_context_entry(*ContextHandle);
*ContextHandle = NULL;
if (che)
{
status = RPC_S_OK;
list_remove(&che->entry);
}
LeaveCriticalSection(&ndr_context_cs);
if (che)
{
RpcBindingFree(&che->handle);
HeapFree(GetProcessHeap(), 0, che);
}
return status;
}
/***********************************************************************
* RpcSsDestroyClientContext [RPCRT4.@]
*/
void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
{
RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
if (status != RPC_S_OK)
RpcRaiseException(status);
}
static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext,
RPC_BINDING_HANDLE hBinding,
const ndr_context_handle *chi)
{
struct context_handle_entry *che = NULL;
/* a null UUID means we should free the context handle */
if (IsEqualGUID(&chi->uuid, &GUID_NULL))
{
if (*CContext)
{
che = get_context_entry(*CContext);
if (!che)
return ERROR_INVALID_HANDLE;
list_remove(&che->entry);
RpcBindingFree(&che->handle);
HeapFree(GetProcessHeap(), 0, che);
che = NULL;
}
}
/* if there's no existing entry matching the GUID, allocate one */
else if (!(che = context_entry_from_guid(&chi->uuid)))
{
che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
if (!che)
return ERROR_NOT_ENOUGH_MEMORY;
che->magic = NDR_CONTEXT_HANDLE_MAGIC;
RpcBindingCopy(hBinding, &che->handle);
list_add_tail(&context_handle_list, &che->entry);
memcpy(&che->wire_data, chi, sizeof *chi);
}
*CContext = che;
return ERROR_SUCCESS;
}
/***********************************************************************
* NDRCContextUnmarshall [RPCRT4.@]
*/
void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
RPC_BINDING_HANDLE hBinding,
void *pBuff, ULONG DataRepresentation)
{
UINT r;
TRACE("*%p=(%p) %p %p %08x\n",
CContext, *CContext, hBinding, pBuff, DataRepresentation);
EnterCriticalSection(&ndr_context_cs);
r = ndr_update_context_handle(CContext, hBinding, pBuff);
LeaveCriticalSection(&ndr_context_cs);
if (r)
RpcRaiseException(r);
}
/***********************************************************************
* NDRSContextMarshall [RPCRT4.@]
*/
void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
void *pBuff,
NDR_RUNDOWN userRunDownIn)
{
TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff, userRunDownIn, NULL, 0);
}
/***********************************************************************
* NDRSContextMarshallEx [RPCRT4.@]
*/
void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
NDR_SCONTEXT SContext,
void *pBuff,
NDR_RUNDOWN userRunDownIn)
{
TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL, 0);
}
/***********************************************************************
* NDRSContextMarshall2 [RPCRT4.@]
*/
void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
NDR_SCONTEXT SContext,
void *pBuff,
NDR_RUNDOWN userRunDownIn,
void *CtxGuard, ULONG Flags)
{
RpcBinding *binding = hBinding;
RPC_STATUS status;
ndr_context_handle *ndr = pBuff;
TRACE("(%p %p %p %p %p %u)\n",
hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
if (!binding->server || !binding->Assoc)
RpcRaiseException(ERROR_INVALID_HANDLE);
if (SContext->userContext)
{
status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
if (status != RPC_S_OK)
RpcRaiseException(status);
ndr->attributes = 0;
RpcContextHandle_GetUuid(SContext, &ndr->uuid);
RPCRT4_RemoveThreadContextHandle(SContext);
RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
}
else
{
if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
RpcRaiseException(ERROR_INVALID_HANDLE);
memset(ndr, 0, sizeof(*ndr));
RPCRT4_RemoveThreadContextHandle(SContext);
/* Note: release the context handle twice in this case to release
* one ref being kept around for the data and one ref for the
* unmarshall/marshall sequence */
if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
return; /* this is to cope with the case of the data not being valid
* before and so not having a further reference */
RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
}
}
/***********************************************************************
* NDRSContextUnmarshall [RPCRT4.@]
*/
NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
ULONG DataRepresentation)
{
TRACE("(%p %08x)\n", pBuff, DataRepresentation);
return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff, DataRepresentation, NULL, 0);
}
/***********************************************************************
* NDRSContextUnmarshallEx [RPCRT4.@]
*/
NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
void *pBuff,
ULONG DataRepresentation)
{
TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL, 0);
}
/***********************************************************************
* NDRSContextUnmarshall2 [RPCRT4.@]
*/
NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
void *pBuff,
ULONG DataRepresentation,
void *CtxGuard, ULONG Flags)
{
RpcBinding *binding = hBinding;
NDR_SCONTEXT SContext;
RPC_STATUS status;
TRACE("(%p %p %08x %p %u)\n",
hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
if (!binding->server || !binding->Assoc)
RpcRaiseException(ERROR_INVALID_HANDLE);
if (!pBuff)
status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
&SContext);
else
{
const ndr_context_handle *context_ndr = pBuff;
if (context_ndr->attributes)
{
ERR("non-null attributes 0x%x\n", context_ndr->attributes);
status = ERROR_INVALID_HANDLE;
}
else
status = RpcServerAssoc_FindContextHandle(binding->Assoc,
&context_ndr->uuid,
CtxGuard, Flags,
&SContext);
}
if (status != RPC_S_OK)
RpcRaiseException(status);
RPCRT4_PushThreadContextHandle(SContext);
return SContext;
}

View file

@ -63,8 +63,14 @@ PFULL_PTR_XLAT_TABLES WINAPI NdrFullPointerXlatInit(ULONG NumberOfPointers,
void WINAPI NdrFullPointerXlatFree(PFULL_PTR_XLAT_TABLES pXlatTables)
{
ULONG i;
TRACE("(%p)\n", pXlatTables);
/* free the entries in the table */
for (i = 0; i < pXlatTables->RefIdToPointer.NumberOfEntries; i++)
HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.XlatTable[i]);
HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.XlatTable);
HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.StateTable);
HeapFree(GetProcessHeap(), 0, pXlatTables->PointerToRefId.XlatTable);

File diff suppressed because it is too large Load diff

View file

@ -82,7 +82,7 @@ typedef struct RpcStreamImpl
DWORD RefCount;
PMIDL_STUB_MESSAGE pMsg;
LPDWORD size;
char *data;
unsigned char *data;
DWORD pos;
} RpcStreamImpl;
@ -145,7 +145,7 @@ static HRESULT WINAPI RpcStream_Write(LPSTREAM iface,
ULONG *pcbWritten)
{
RpcStreamImpl *This = (RpcStreamImpl *)iface;
if (This->data + cb > (char *)This->pMsg->BufferEnd)
if (This->data + cb > (unsigned char *)This->pMsg->RpcMsg->Buffer + This->pMsg->BufferLength)
return STG_E_MEDIUMFULL;
memcpy(This->data + This->pos, pv, cb);
This->pos += cb;
@ -215,7 +215,7 @@ static LPSTREAM RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init)
This->RefCount = 1;
This->pMsg = pStubMsg;
This->size = (LPDWORD)pStubMsg->Buffer;
This->data = (char*)(This->size + 1);
This->data = (unsigned char*)(This->size + 1);
This->pos = 0;
if (init) *This->size = 0;
TRACE("init size=%d\n", *This->size);

View file

@ -42,8 +42,9 @@
#include "wine/debug.h"
#include "wine/rpcfc.h"
#include "ndr_misc.h"
#include "cpsf.h"
#include "ndr_misc.h"
#include "ndr_stubless.h"
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
@ -113,9 +114,6 @@ static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORM
}
}
/* there can't be any alignment with the structures in this file */
#include "pshpack1.h"
#define STUBLESS_UNMARSHAL 1
#define STUBLESS_CALLSERVER 2
#define STUBLESS_CALCSIZE 3
@ -123,220 +121,6 @@ static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORM
#define STUBLESS_MARSHAL 5
#define STUBLESS_FREE 6
/* From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/parameter_descriptors.asp */
typedef struct _NDR_PROC_HEADER
{
/* type of handle to use:
* RPC_FC_BIND_EXPLICIT = 0 - Explicit handle.
* Handle is passed as a parameter to the function.
* Indicates that explicit handle information follows the header,
* which actually describes the handle.
* RPC_FC_BIND_GENERIC = 31 - Implicit handle with custom binding routines
* (MIDL_STUB_DESC::IMPLICIT_HANDLE_INFO::pGenericBindingInfo)
* RPC_FC_BIND_PRIMITIVE = 32 - Implicit handle using handle_t created by
* calling application
* RPC_FC_AUTO_HANDLE = 33 - Automatic handle
* RPC_FC_CALLBACK_HANDLE = 34 - undocmented
*/
unsigned char handle_type;
/* procedure flags:
* Oi_FULL_PTR_USED = 0x01 - A full pointer can have the value NULL and can
* change during the call from NULL to non-NULL and supports aliasing
* and cycles. Indicates that the NdrFullPointerXlatInit function
* should be called.
* Oi_RPCSS_ALLOC_USED = 0x02 - Use RpcSS allocate/free routines instead of
* normal allocate/free routines
* Oi_OBJECT_PROC = 0x04 - Indicates a procedure that is part of an OLE
* interface, rather than a DCE RPC interface.
* Oi_HAS_RPCFLAGS = 0x08 - Indicates that the rpc_flags element is
* present in the header.
* Oi_HAS_COMM_OR_FAULT = 0x20 - If Oi_OBJECT_PROC not present only then
* indicates that the procedure has the comm_status or fault_status
* MIDL attribute.
* Oi_OBJ_USE_V2_INTERPRETER = 0x20 - If Oi_OBJECT_PROC present only
* then indicates that the format string is in -Oif or -Oicf format
* Oi_USE_NEW_INIT_ROUTINES = 0x40 - Use NdrXInitializeNew instead of
* NdrXInitialize?
*/
unsigned char Oi_flags;
/* the zero-based index of the procedure */
unsigned short proc_num;
/* total size of all parameters on the stack, including any "this"
* pointer and/or return value */
unsigned short stack_size;
} NDR_PROC_HEADER;
/* same as above struct except additional element rpc_flags */
typedef struct _NDR_PROC_HEADER_RPC
{
unsigned char handle_type;
unsigned char Oi_flags;
/*
* RPCF_Idempotent = 0x0001 - [idempotent] MIDL attribute
* RPCF_Broadcast = 0x0002 - [broadcast] MIDL attribute
* RPCF_Maybe = 0x0004 - [maybe] MIDL attribute
* Reserved = 0x0008 - 0x0080
* RPCF_Message = 0x0100 - [message] MIDL attribute
* Reserved = 0x0200 - 0x1000
* RPCF_InputSynchronous = 0x2000 - unknown
* RPCF_Asynchronous = 0x4000 - [async] MIDL attribute
* Reserved = 0x8000
*/
unsigned long rpc_flags;
unsigned short proc_num;
unsigned short stack_size;
} NDR_PROC_HEADER_RPC;
typedef struct _NDR_PROC_PARTIAL_OIF_HEADER
{
/* the pre-computed client buffer size so that interpreter can skip all
* or some (if the flag RPC_FC_PROC_OI2F_CLTMUSTSIZE is specified) of the
* sizing pass */
unsigned short constant_client_buffer_size;
/* the pre-computed server buffer size so that interpreter can skip all
* or some (if the flag RPC_FC_PROC_OI2F_SRVMUSTSIZE is specified) of the
* sizing pass */
unsigned short constant_server_buffer_size;
INTERPRETER_OPT_FLAGS Oi2Flags;
/* number of params */
unsigned char number_of_params;
} NDR_PROC_PARTIAL_OIF_HEADER;
typedef struct _NDR_PARAM_OI_BASETYPE
{
/* parameter direction. One of:
* FC_IN_PARAM_BASETYPE = 0x4e - an in param
* FC_RETURN_PARAM_BASETYPE = 0x53 - a return param
*/
unsigned char param_direction;
/* One of: FC_BYTE,FC_CHAR,FC_SMALL,FC_USMALL,FC_WCHAR,FC_SHORT,FC_USHORT,
* FC_LONG,FC_ULONG,FC_FLOAT,FC_HYPER,FC_DOUBLE,FC_ENUM16,FC_ENUM32,
* FC_ERROR_STATUS_T,FC_INT3264,FC_UINT3264 */
unsigned char type_format_char;
} NDR_PARAM_OI_BASETYPE;
typedef struct _NDR_PARAM_OI_OTHER
{
/* One of:
* FC_IN_PARAM = 0x4d - An in param
* FC_IN_OUT_PARAM = 0x50 - An in/out param
* FC_OUT_PARAM = 0x51 - An out param
* FC_RETURN_PARAM = 0x52 - A return value
* FC_IN_PARAM_NO_FREE_INST = 0x4f - A param for which no freeing is done
*/
unsigned char param_direction;
/* Size of param on stack in NUMBERS OF INTS */
unsigned char stack_size;
/* offset in the type format string table */
unsigned short type_offset;
} NDR_PARAM_OI_OTHER;
typedef struct _NDR_PARAM_OIF_BASETYPE
{
PARAM_ATTRIBUTES param_attributes;
/* the offset on the calling stack where the parameter is located */
unsigned short stack_offset;
/* see NDR_PARAM_OI_BASETYPE::type_format_char */
unsigned char type_format_char;
/* always FC_PAD */
unsigned char unused;
} NDR_PARAM_OIF_BASETYPE;
typedef struct _NDR_PARAM_OIF_OTHER
{
PARAM_ATTRIBUTES param_attributes;
/* see NDR_PARAM_OIF_BASETYPE::stack_offset */
unsigned short stack_offset;
/* offset into the provided type format string where the type for this
* parameter starts */
unsigned short type_offset;
} NDR_PARAM_OIF_OTHER;
/* explicit handle description for FC_BIND_PRIMITIVE type */
typedef struct _NDR_EHD_PRIMITIVE
{
/* FC_BIND_PRIMITIVE */
unsigned char handle_type;
/* is the handle passed in via a pointer? */
unsigned char flag;
/* offset from the beginning of the stack to the handle in bytes */
unsigned short offset;
} NDR_EHD_PRIMITIVE;
/* explicit handle description for FC_BIND_GENERIC type */
typedef struct _NDR_EHD_GENERIC
{
/* FC_BIND_GENERIC */
unsigned char handle_type;
/* upper 4bits is a flag indicating whether the handle is passed in
* via a pointer. lower 4bits is the size of the user defined generic
* handle type. the size must be less than or equal to the machine
* register size */
unsigned char flag_and_size;
/* offset from the beginning of the stack to the handle in bytes */
unsigned short offset;
/* the index into the aGenericBindingRoutinesPairs field of MIDL_STUB_DESC
* giving the bind and unbind routines for the handle */
unsigned char binding_routine_pair_index;
/* FC_PAD */
unsigned char unused;
} NDR_EHD_GENERIC;
/* explicit handle description for FC_BIND_CONTEXT type */
typedef struct _NDR_EHD_CONTEXT
{
/* FC_BIND_CONTEXT */
unsigned char handle_type;
/* Any of the following flags:
* NDR_CONTEXT_HANDLE_CANNOT_BE_NULL = 0x01
* NDR_CONTEXT_HANDLE_SERIALIZE = 0x02
* NDR_CONTEXT_HANDLE_NO_SERIALIZE = 0x04
* NDR_STRICT_CONTEXT_HANDLE = 0x08
* HANDLE_PARAM_IS_OUT = 0x20
* HANDLE_PARAM_IS_RETURN = 0x21
* HANDLE_PARAM_IS_IN = 0x40
* HANDLE_PARAM_IS_VIA_PTR = 0x80
*/
unsigned char flags;
/* offset from the beginning of the stack to the handle in bytes */
unsigned short offset;
/* zero-based index on rundown routine in apfnNdrRundownRoutines field
* of MIDL_STUB_DESC */
unsigned char context_rundown_routine_index;
/* varies depending on NDR version used.
* V1: zero-based index into parameters
* V2: zero-based index into handles that are parameters */
unsigned char param_num;
} NDR_EHD_CONTEXT;
#include "poppack.h"
void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
{
#if 0 /* these functions are not defined yet */
@ -1075,7 +859,313 @@ static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
return size;
}
/* FIXME: need to free some stuff in here too */
static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
PFORMAT_STRING pFormat, int phase,
unsigned char *args,
unsigned short number_of_params)
{
/* counter */
unsigned short i;
/* current format string offset */
int current_offset = 0;
/* current stack offset */
unsigned short current_stack_offset = 0;
/* location to put retval into */
LONG_PTR *retval_ptr = NULL;
for (i = 0; i < number_of_params; i++)
{
const NDR_PARAM_OIF_BASETYPE *pParam =
(const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
unsigned char *pArg;
current_stack_offset = pParam->stack_offset;
pArg = (unsigned char *)(args+current_stack_offset);
TRACE("param[%d]: new format\n", i);
TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg);
if (pParam->param_attributes.IsBasetype)
{
const unsigned char *pTypeFormat =
&pParam->type_format_char;
TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsSimpleRef)
call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
else
call_marshaller(pStubMsg, pArg, pTypeFormat);
}
break;
case STUBLESS_FREE:
if (pParam->param_attributes.ServerAllocSize)
HeapFree(GetProcessHeap(), 0, *(void **)pArg);
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_attributes.ServerAllocSize)
*(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
pParam->param_attributes.ServerAllocSize * 8);
if (pParam->param_attributes.IsIn)
{
if (pParam->param_attributes.IsSimpleRef)
call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
else
call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
}
/* make a note of the address of the return value parameter for later */
if (pParam->param_attributes.IsReturn)
retval_ptr = (LONG_PTR *)pArg;
break;
case STUBLESS_CALCSIZE:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsSimpleRef)
call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
else
call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
}
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
}
else
{
const NDR_PARAM_OIF_OTHER *pParamOther =
(const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
const unsigned char * pTypeFormat =
&(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]);
TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsByValue)
call_marshaller(pStubMsg, pArg, pTypeFormat);
else
call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
}
break;
case STUBLESS_FREE:
if (pParam->param_attributes.MustFree)
{
if (pParam->param_attributes.IsByValue)
call_freer(pStubMsg, pArg, pTypeFormat);
else
call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
}
if (pParam->param_attributes.IsOut &&
!pParam->param_attributes.IsIn &&
!pParam->param_attributes.IsByValue &&
!pParam->param_attributes.ServerAllocSize)
{
pStubMsg->pfnFree(*(void **)pArg);
}
if (pParam->param_attributes.ServerAllocSize)
HeapFree(GetProcessHeap(), 0, *(void **)pArg);
/* FIXME: call call_freer here for IN types with MustFree set */
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_attributes.ServerAllocSize)
*(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
pParam->param_attributes.ServerAllocSize * 8);
if (pParam->param_attributes.IsIn)
{
if (pParam->param_attributes.IsByValue)
call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
else
call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
}
else if (pParam->param_attributes.IsOut &&
!pParam->param_attributes.ServerAllocSize &&
!pParam->param_attributes.IsByValue)
{
DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
if(size)
{
*(void **)pArg = NdrAllocate(pStubMsg, size);
memset(*(void **)pArg, 0, size);
}
}
break;
case STUBLESS_CALCSIZE:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsByValue)
call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
else
call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
}
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_offset += sizeof(NDR_PARAM_OIF_OTHER);
}
TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
}
return retval_ptr;
}
static LONG_PTR *stub_do_old_args(MIDL_STUB_MESSAGE *pStubMsg,
PFORMAT_STRING pFormat, int phase,
unsigned char *args,
unsigned short stack_size, BOOL object)
{
/* counter */
unsigned short i;
/* current format string offset */
int current_offset = 0;
/* current stack offset */
unsigned short current_stack_offset = 0;
/* location to put retval into */
LONG_PTR *retval_ptr = NULL;
for (i = 0; TRUE; i++)
{
const NDR_PARAM_OI_BASETYPE *pParam =
(const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
/* note: current_stack_offset starts after the This pointer
* if present, so adjust this */
unsigned short current_stack_offset_adjusted = current_stack_offset +
(object ? sizeof(void *) : 0);
unsigned char *pArg = (unsigned char *)(args+current_stack_offset_adjusted);
/* no more parameters; exit loop */
if (current_stack_offset_adjusted >= stack_size)
break;
TRACE("param[%d]: old format\n", i);
TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
{
const unsigned char *pTypeFormat =
&pParam->type_format_char;
TRACE("\tbase type 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
call_marshaller(pStubMsg, pArg, pTypeFormat);
break;
case STUBLESS_FREE:
if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
call_freer(pStubMsg, pArg, pTypeFormat);
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0);
else if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
retval_ptr = (LONG_PTR *)pArg;
break;
case STUBLESS_CALCSIZE:
if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
call_buffer_sizer(pStubMsg, pArg, pTypeFormat);
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat);
current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
}
else
{
const NDR_PARAM_OI_OTHER *pParamOther =
(const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
const unsigned char * pTypeFormat =
&pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset];
TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_direction == RPC_FC_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_RETURN_PARAM)
call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
break;
case STUBLESS_FREE:
if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_PARAM)
call_freer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
else if (pParam->param_direction == RPC_FC_OUT_PARAM)
pStubMsg->pfnFree(*(void **)pArg);
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_PARAM)
call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0);
else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
retval_ptr = (LONG_PTR *)pArg;
else if (pParam->param_direction == RPC_FC_OUT_PARAM)
{
DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
if(size)
{
*(void **)pArg = NdrAllocate(pStubMsg, size);
memset(*(void **)pArg, 0, size);
}
}
break;
case STUBLESS_CALCSIZE:
if (pParam->param_direction == RPC_FC_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_RETURN_PARAM)
call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat);
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_stack_offset += pParamOther->stack_size * sizeof(INT);
current_offset += sizeof(NDR_PARAM_OI_OTHER);
}
}
return retval_ptr;
}
/***********************************************************************
* NdrStubCall2 [RPCRT4.@]
*
* Unmarshals [in] parameters, calls either a method in an object or a server
* function, marshals any [out] parameters and frees any allocated data.
*
* NOTES
* Used by stubless MIDL-generated code.
*/
LONG WINAPI NdrStubCall2(
struct IRpcStubBuffer * pThis,
struct IRpcChannelBuffer * pChannel,
@ -1090,12 +1180,8 @@ LONG WINAPI NdrStubCall2(
unsigned char * args;
/* size of stack */
unsigned short stack_size;
/* current stack offset */
unsigned short current_stack_offset;
/* number of parameters. optional for client to give it to us */
unsigned char number_of_params = ~0;
/* counter */
unsigned short i;
/* cache of Oif_flags from v2 procedure header */
INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
/* cache of extension flags from NDR_PROC_HEADER_EXTS */
@ -1318,278 +1404,13 @@ LONG WINAPI NdrStubCall2(
case STUBLESS_UNMARSHAL:
case STUBLESS_CALCSIZE:
case STUBLESS_FREE:
current_offset = parameter_start_offset;
current_stack_offset = 0;
/* NOTE: V1 style format does't terminate on the number_of_params
* condition as it doesn't have this attribute. Instead it
* terminates when the stack size given in the header is exceeded.
*/
for (i = 0; i < number_of_params; i++)
{
if (bV2Format) /* new parameter format */
{
const NDR_PARAM_OIF_BASETYPE *pParam =
(const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset];
unsigned char *pArg;
current_stack_offset = pParam->stack_offset;
pArg = (unsigned char *)(args+current_stack_offset);
TRACE("param[%d]: new format\n", i);
TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n");
TRACE("\tstack_offset: 0x%x\n", current_stack_offset);
TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg);
if (pParam->param_attributes.IsBasetype)
{
const unsigned char *pTypeFormat =
&pParam->type_format_char;
TRACE("\tbase type: 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsSimpleRef)
call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
if (bV2Format)
retval_ptr = stub_do_args(&stubMsg, &pFormat[parameter_start_offset],
phase, args, number_of_params);
else
call_marshaller(&stubMsg, pArg, pTypeFormat);
}
break;
case STUBLESS_FREE:
if (pParam->param_attributes.ServerAllocSize)
HeapFree(GetProcessHeap(), 0, *(void **)pArg);
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_attributes.ServerAllocSize)
*(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
pParam->param_attributes.ServerAllocSize * 8);
if (pParam->param_attributes.IsIn)
{
if (pParam->param_attributes.IsSimpleRef)
call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0);
else
call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0);
}
/* make a note of the address of the return value parameter for later */
if (pParam->param_attributes.IsReturn)
retval_ptr = (LONG_PTR *)pArg;
break;
case STUBLESS_CALCSIZE:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsSimpleRef)
call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
else
call_buffer_sizer(&stubMsg, pArg, pTypeFormat);
}
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_offset += sizeof(NDR_PARAM_OIF_BASETYPE);
}
else
{
const NDR_PARAM_OIF_OTHER *pParamOther =
(const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset];
const unsigned char * pTypeFormat =
&(pStubDesc->pFormatTypes[pParamOther->type_offset]);
TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsByValue)
call_marshaller(&stubMsg, pArg, pTypeFormat);
else
call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
}
break;
case STUBLESS_FREE:
if (pParam->param_attributes.MustFree)
{
if (pParam->param_attributes.IsByValue)
call_freer(&stubMsg, pArg, pTypeFormat);
else
call_freer(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
}
if (pParam->param_attributes.IsOut &&
!pParam->param_attributes.IsIn &&
!pParam->param_attributes.IsByValue &&
!pParam->param_attributes.ServerAllocSize)
{
stubMsg.pfnFree(*(void **)pArg);
}
if (pParam->param_attributes.ServerAllocSize)
HeapFree(GetProcessHeap(), 0, *(void **)pArg);
/* FIXME: call call_freer here for IN types with MustFree set */
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_attributes.ServerAllocSize)
*(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
pParam->param_attributes.ServerAllocSize * 8);
if (pParam->param_attributes.IsIn)
{
if (pParam->param_attributes.IsByValue)
call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0);
else
call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0);
}
else if (pParam->param_attributes.IsOut &&
!pParam->param_attributes.ServerAllocSize &&
!pParam->param_attributes.IsByValue)
{
DWORD size = calc_arg_size(&stubMsg, pTypeFormat);
if(size)
{
*(void **)pArg = NdrAllocate(&stubMsg, size);
memset(*(void **)pArg, 0, size);
}
}
break;
case STUBLESS_CALCSIZE:
if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn)
{
if (pParam->param_attributes.IsByValue)
call_buffer_sizer(&stubMsg, pArg, pTypeFormat);
else
call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
}
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_offset += sizeof(NDR_PARAM_OIF_OTHER);
}
TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
}
else /* old parameter format */
{
const NDR_PARAM_OI_BASETYPE *pParam =
(const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset];
/* note: current_stack_offset starts after the This pointer
* if present, so adjust this */
unsigned short current_stack_offset_adjusted = current_stack_offset +
((pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) ? sizeof(void *) : 0);
unsigned char *pArg = (unsigned char *)(args+current_stack_offset_adjusted);
/* no more parameters; exit loop */
if (current_stack_offset_adjusted >= stack_size)
break;
TRACE("param[%d]: old format\n", i);
TRACE("\tparam_direction: 0x%x\n", pParam->param_direction);
TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted);
if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE ||
pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
{
const unsigned char *pTypeFormat =
&pParam->type_format_char;
TRACE("\tbase type 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
call_marshaller(&stubMsg, pArg, pTypeFormat);
break;
case STUBLESS_FREE:
if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
call_freer(&stubMsg, pArg, pTypeFormat);
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE)
call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0);
else if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
retval_ptr = (LONG_PTR *)pArg;
break;
case STUBLESS_CALCSIZE:
if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE)
call_buffer_sizer(&stubMsg, pArg, pTypeFormat);
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_stack_offset += call_memory_sizer(&stubMsg, pTypeFormat);
current_offset += sizeof(NDR_PARAM_OI_BASETYPE);
}
else
{
const NDR_PARAM_OI_OTHER *pParamOther =
(const NDR_PARAM_OI_OTHER *)&pFormat[current_offset];
const unsigned char * pTypeFormat =
&pStubDesc->pFormatTypes[pParamOther->type_offset];
TRACE("\tcomplex type 0x%02x\n", *pTypeFormat);
switch (phase)
{
case STUBLESS_MARSHAL:
if (pParam->param_direction == RPC_FC_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_RETURN_PARAM)
call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
break;
case STUBLESS_FREE:
if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_PARAM)
call_freer(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
else if (pParam->param_direction == RPC_FC_OUT_PARAM)
stubMsg.pfnFree(*(void **)pArg);
break;
case STUBLESS_UNMARSHAL:
if (pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_PARAM)
call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0);
else if (pParam->param_direction == RPC_FC_RETURN_PARAM)
retval_ptr = (LONG_PTR *)pArg;
else if (pParam->param_direction == RPC_FC_OUT_PARAM)
{
DWORD size = calc_arg_size(&stubMsg, pTypeFormat);
if(size)
{
*(void **)pArg = NdrAllocate(&stubMsg, size);
memset(*(void **)pArg, 0, size);
}
}
break;
case STUBLESS_CALCSIZE:
if (pParam->param_direction == RPC_FC_OUT_PARAM ||
pParam->param_direction == RPC_FC_IN_OUT_PARAM ||
pParam->param_direction == RPC_FC_RETURN_PARAM)
call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat);
break;
default:
RpcRaiseException(RPC_S_INTERNAL_ERROR);
}
current_stack_offset += pParamOther->stack_size * sizeof(INT);
current_offset += sizeof(NDR_PARAM_OI_OTHER);
}
}
}
retval_ptr = stub_do_old_args(&stubMsg, &pFormat[parameter_start_offset],
phase, args, stack_size,
(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT));
break;
default:
@ -1621,6 +1442,9 @@ LONG WINAPI NdrStubCall2(
return S_OK;
}
/***********************************************************************
* NdrServerCall2 [RPCRT4.@]
*/
void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
{
DWORD dwPhase;

View file

@ -0,0 +1,236 @@
/*
* NDR -Oi,-Oif,-Oicf Interpreter
*
* Copyright 2007 Robert Shearman (for CodeWeavers)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* there can't be any alignment with the structures in this file */
#include "pshpack1.h"
/* From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/parameter_descriptors.asp */
typedef struct _NDR_PROC_HEADER
{
/* type of handle to use:
* RPC_FC_BIND_EXPLICIT = 0 - Explicit handle.
* Handle is passed as a parameter to the function.
* Indicates that explicit handle information follows the header,
* which actually describes the handle.
* RPC_FC_BIND_GENERIC = 31 - Implicit handle with custom binding routines
* (MIDL_STUB_DESC::IMPLICIT_HANDLE_INFO::pGenericBindingInfo)
* RPC_FC_BIND_PRIMITIVE = 32 - Implicit handle using handle_t created by
* calling application
* RPC_FC_AUTO_HANDLE = 33 - Automatic handle
* RPC_FC_CALLBACK_HANDLE = 34 - undocmented
*/
unsigned char handle_type;
/* procedure flags:
* Oi_FULL_PTR_USED = 0x01 - A full pointer can have the value NULL and can
* change during the call from NULL to non-NULL and supports aliasing
* and cycles. Indicates that the NdrFullPointerXlatInit function
* should be called.
* Oi_RPCSS_ALLOC_USED = 0x02 - Use RpcSS allocate/free routines instead of
* normal allocate/free routines
* Oi_OBJECT_PROC = 0x04 - Indicates a procedure that is part of an OLE
* interface, rather than a DCE RPC interface.
* Oi_HAS_RPCFLAGS = 0x08 - Indicates that the rpc_flags element is
* present in the header.
* Oi_HAS_COMM_OR_FAULT = 0x20 - If Oi_OBJECT_PROC not present only then
* indicates that the procedure has the comm_status or fault_status
* MIDL attribute.
* Oi_OBJ_USE_V2_INTERPRETER = 0x20 - If Oi_OBJECT_PROC present only
* then indicates that the format string is in -Oif or -Oicf format
* Oi_USE_NEW_INIT_ROUTINES = 0x40 - Use NdrXInitializeNew instead of
* NdrXInitialize?
*/
unsigned char Oi_flags;
/* the zero-based index of the procedure */
unsigned short proc_num;
/* total size of all parameters on the stack, including any "this"
* pointer and/or return value */
unsigned short stack_size;
} NDR_PROC_HEADER;
/* same as above struct except additional element rpc_flags */
typedef struct _NDR_PROC_HEADER_RPC
{
unsigned char handle_type;
unsigned char Oi_flags;
/*
* RPCF_Idempotent = 0x0001 - [idempotent] MIDL attribute
* RPCF_Broadcast = 0x0002 - [broadcast] MIDL attribute
* RPCF_Maybe = 0x0004 - [maybe] MIDL attribute
* Reserved = 0x0008 - 0x0080
* RPCF_Message = 0x0100 - [message] MIDL attribute
* Reserved = 0x0200 - 0x1000
* RPCF_InputSynchronous = 0x2000 - unknown
* RPCF_Asynchronous = 0x4000 - [async] MIDL attribute
* Reserved = 0x8000
*/
unsigned long rpc_flags;
unsigned short proc_num;
unsigned short stack_size;
} NDR_PROC_HEADER_RPC;
typedef struct _NDR_PROC_PARTIAL_OIF_HEADER
{
/* the pre-computed client buffer size so that interpreter can skip all
* or some (if the flag RPC_FC_PROC_OI2F_CLTMUSTSIZE is specified) of the
* sizing pass */
unsigned short constant_client_buffer_size;
/* the pre-computed server buffer size so that interpreter can skip all
* or some (if the flag RPC_FC_PROC_OI2F_SRVMUSTSIZE is specified) of the
* sizing pass */
unsigned short constant_server_buffer_size;
INTERPRETER_OPT_FLAGS Oi2Flags;
/* number of params */
unsigned char number_of_params;
} NDR_PROC_PARTIAL_OIF_HEADER;
typedef struct _NDR_PARAM_OI_BASETYPE
{
/* parameter direction. One of:
* FC_IN_PARAM_BASETYPE = 0x4e - an in param
* FC_RETURN_PARAM_BASETYPE = 0x53 - a return param
*/
unsigned char param_direction;
/* One of: FC_BYTE,FC_CHAR,FC_SMALL,FC_USMALL,FC_WCHAR,FC_SHORT,FC_USHORT,
* FC_LONG,FC_ULONG,FC_FLOAT,FC_HYPER,FC_DOUBLE,FC_ENUM16,FC_ENUM32,
* FC_ERROR_STATUS_T,FC_INT3264,FC_UINT3264 */
unsigned char type_format_char;
} NDR_PARAM_OI_BASETYPE;
typedef struct _NDR_PARAM_OI_OTHER
{
/* One of:
* FC_IN_PARAM = 0x4d - An in param
* FC_IN_OUT_PARAM = 0x50 - An in/out param
* FC_OUT_PARAM = 0x51 - An out param
* FC_RETURN_PARAM = 0x52 - A return value
* FC_IN_PARAM_NO_FREE_INST = 0x4f - A param for which no freeing is done
*/
unsigned char param_direction;
/* Size of param on stack in NUMBERS OF INTS */
unsigned char stack_size;
/* offset in the type format string table */
unsigned short type_offset;
} NDR_PARAM_OI_OTHER;
typedef struct _NDR_PARAM_OIF_BASETYPE
{
PARAM_ATTRIBUTES param_attributes;
/* the offset on the calling stack where the parameter is located */
unsigned short stack_offset;
/* see NDR_PARAM_OI_BASETYPE::type_format_char */
unsigned char type_format_char;
/* always FC_PAD */
unsigned char unused;
} NDR_PARAM_OIF_BASETYPE;
typedef struct _NDR_PARAM_OIF_OTHER
{
PARAM_ATTRIBUTES param_attributes;
/* see NDR_PARAM_OIF_BASETYPE::stack_offset */
unsigned short stack_offset;
/* offset into the provided type format string where the type for this
* parameter starts */
unsigned short type_offset;
} NDR_PARAM_OIF_OTHER;
/* explicit handle description for FC_BIND_PRIMITIVE type */
typedef struct _NDR_EHD_PRIMITIVE
{
/* FC_BIND_PRIMITIVE */
unsigned char handle_type;
/* is the handle passed in via a pointer? */
unsigned char flag;
/* offset from the beginning of the stack to the handle in bytes */
unsigned short offset;
} NDR_EHD_PRIMITIVE;
/* explicit handle description for FC_BIND_GENERIC type */
typedef struct _NDR_EHD_GENERIC
{
/* FC_BIND_GENERIC */
unsigned char handle_type;
/* upper 4bits is a flag indicating whether the handle is passed in
* via a pointer. lower 4bits is the size of the user defined generic
* handle type. the size must be less than or equal to the machine
* register size */
unsigned char flag_and_size;
/* offset from the beginning of the stack to the handle in bytes */
unsigned short offset;
/* the index into the aGenericBindingRoutinesPairs field of MIDL_STUB_DESC
* giving the bind and unbind routines for the handle */
unsigned char binding_routine_pair_index;
/* FC_PAD */
unsigned char unused;
} NDR_EHD_GENERIC;
/* explicit handle description for FC_BIND_CONTEXT type */
typedef struct _NDR_EHD_CONTEXT
{
/* FC_BIND_CONTEXT */
unsigned char handle_type;
/* Any of the following flags:
* NDR_CONTEXT_HANDLE_CANNOT_BE_NULL = 0x01
* NDR_CONTEXT_HANDLE_SERIALIZE = 0x02
* NDR_CONTEXT_HANDLE_NO_SERIALIZE = 0x04
* NDR_STRICT_CONTEXT_HANDLE = 0x08
* HANDLE_PARAM_IS_OUT = 0x20
* HANDLE_PARAM_IS_RETURN = 0x21
* HANDLE_PARAM_IS_IN = 0x40
* HANDLE_PARAM_IS_VIA_PTR = 0x80
*/
unsigned char flags;
/* offset from the beginning of the stack to the handle in bytes */
unsigned short offset;
/* zero-based index on rundown routine in apfnNdrRundownRoutines field
* of MIDL_STUB_DESC */
unsigned char context_rundown_routine_index;
/* varies depending on NDR version used.
* V1: zero-based index into parameters
* V2: zero-based index into handles that are parameters */
unsigned char param_num;
} NDR_EHD_CONTEXT;
#include "poppack.h"

View file

@ -0,0 +1,539 @@
/*
* Associations
*
* Copyright 2007 Robert Shearman (for CodeWeavers)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include <stdarg.h>
#include <assert.h>
#include "rpc.h"
#include "rpcndr.h"
#include "winternl.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "rpc_binding.h"
#include "rpc_assoc.h"
#include "rpc_message.h"
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
static CRITICAL_SECTION assoc_list_cs;
static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
{
0, 0, &assoc_list_cs,
{ &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }
};
static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
static struct list client_assoc_list = LIST_INIT(client_assoc_list);
static struct list server_assoc_list = LIST_INIT(server_assoc_list);
static LONG last_assoc_group_id;
typedef struct _RpcContextHandle
{
struct list entry;
void *user_context;
NDR_RUNDOWN rundown_routine;
void *ctx_guard;
UUID uuid;
RTL_RWLOCK rw_lock;
unsigned int refs;
} RpcContextHandle;
static void RpcContextHandle_Destroy(RpcContextHandle *context_handle);
static RPC_STATUS RpcAssoc_Alloc(LPCSTR Protseq, LPCSTR NetworkAddr,
LPCSTR Endpoint, LPCWSTR NetworkOptions,
RpcAssoc **assoc_out)
{
RpcAssoc *assoc;
assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
if (!assoc)
return RPC_S_OUT_OF_RESOURCES;
assoc->refs = 1;
list_init(&assoc->free_connection_pool);
list_init(&assoc->context_handle_list);
InitializeCriticalSection(&assoc->cs);
assoc->Protseq = RPCRT4_strdupA(Protseq);
assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
assoc->Endpoint = RPCRT4_strdupA(Endpoint);
assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL;
assoc->assoc_group_id = 0;
list_init(&assoc->entry);
*assoc_out = assoc;
return RPC_S_OK;
}
RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
LPCSTR Endpoint, LPCWSTR NetworkOptions,
RpcAssoc **assoc_out)
{
RpcAssoc *assoc;
RPC_STATUS status;
EnterCriticalSection(&assoc_list_cs);
LIST_FOR_EACH_ENTRY(assoc, &client_assoc_list, RpcAssoc, entry)
{
if (!strcmp(Protseq, assoc->Protseq) &&
!strcmp(NetworkAddr, assoc->NetworkAddr) &&
!strcmp(Endpoint, assoc->Endpoint) &&
((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions)))
{
assoc->refs++;
*assoc_out = assoc;
LeaveCriticalSection(&assoc_list_cs);
TRACE("using existing assoc %p\n", assoc);
return RPC_S_OK;
}
}
status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc);
if (status != RPC_S_OK)
{
LeaveCriticalSection(&assoc_list_cs);
return status;
}
list_add_head(&client_assoc_list, &assoc->entry);
*assoc_out = assoc;
LeaveCriticalSection(&assoc_list_cs);
TRACE("new assoc %p\n", assoc);
return RPC_S_OK;
}
RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
LPCSTR Endpoint, LPCWSTR NetworkOptions,
unsigned long assoc_gid,
RpcAssoc **assoc_out)
{
RpcAssoc *assoc;
RPC_STATUS status;
EnterCriticalSection(&assoc_list_cs);
if (assoc_gid)
{
LIST_FOR_EACH_ENTRY(assoc, &server_assoc_list, RpcAssoc, entry)
{
/* FIXME: NetworkAddr shouldn't be NULL */
if (assoc->assoc_group_id == assoc_gid &&
!strcmp(Protseq, assoc->Protseq) &&
(!NetworkAddr || !assoc->NetworkAddr || !strcmp(NetworkAddr, assoc->NetworkAddr)) &&
!strcmp(Endpoint, assoc->Endpoint) &&
((!assoc->NetworkOptions == !NetworkOptions) &&
(!NetworkOptions || !strcmpW(NetworkOptions, assoc->NetworkOptions))))
{
assoc->refs++;
*assoc_out = assoc;
LeaveCriticalSection(&assoc_list_cs);
TRACE("using existing assoc %p\n", assoc);
return RPC_S_OK;
}
}
*assoc_out = NULL;
LeaveCriticalSection(&assoc_list_cs);
return RPC_S_NO_CONTEXT_AVAILABLE;
}
status = RpcAssoc_Alloc(Protseq, NetworkAddr, Endpoint, NetworkOptions, &assoc);
if (status != RPC_S_OK)
{
LeaveCriticalSection(&assoc_list_cs);
return status;
}
assoc->assoc_group_id = InterlockedIncrement(&last_assoc_group_id);
list_add_head(&server_assoc_list, &assoc->entry);
*assoc_out = assoc;
LeaveCriticalSection(&assoc_list_cs);
TRACE("new assoc %p\n", assoc);
return RPC_S_OK;
}
ULONG RpcAssoc_Release(RpcAssoc *assoc)
{
ULONG refs;
EnterCriticalSection(&assoc_list_cs);
refs = --assoc->refs;
if (!refs)
list_remove(&assoc->entry);
LeaveCriticalSection(&assoc_list_cs);
if (!refs)
{
RpcConnection *Connection, *cursor2;
RpcContextHandle *context_handle, *context_handle_cursor;
TRACE("destroying assoc %p\n", assoc);
LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->free_connection_pool, RpcConnection, conn_pool_entry)
{
list_remove(&Connection->conn_pool_entry);
RPCRT4_DestroyConnection(Connection);
}
LIST_FOR_EACH_ENTRY_SAFE(context_handle, context_handle_cursor, &assoc->context_handle_list, RpcContextHandle, entry)
RpcContextHandle_Destroy(context_handle);
HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions);
HeapFree(GetProcessHeap(), 0, assoc->Endpoint);
HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr);
HeapFree(GetProcessHeap(), 0, assoc->Protseq);
DeleteCriticalSection(&assoc->cs);
HeapFree(GetProcessHeap(), 0, assoc);
}
return refs;
}
#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn,
const RPC_SYNTAX_IDENTIFIER *InterfaceId,
const RPC_SYNTAX_IDENTIFIER *TransferSyntax)
{
RpcPktHdr *hdr;
RpcPktHdr *response_hdr;
RPC_MESSAGE msg;
RPC_STATUS status;
TRACE("sending bind request to server\n");
hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
assoc->assoc_group_id,
InterfaceId, TransferSyntax);
status = RPCRT4_Send(conn, hdr, NULL, 0);
RPCRT4_FreeHeader(hdr);
if (status != RPC_S_OK)
return status;
status = RPCRT4_Receive(conn, &response_hdr, &msg);
if (status != RPC_S_OK)
{
ERR("receive failed\n");
return status;
}
switch (response_hdr->common.ptype)
{
case PKT_BIND_ACK:
{
RpcAddressString *server_address = msg.Buffer;
if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) ||
(msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)))
{
unsigned short remaining = msg.BufferLength -
ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4);
RpcResults *results = (RpcResults*)((ULONG_PTR)server_address +
ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
if ((results->num_results == 1) && (remaining >= sizeof(*results)))
{
switch (results->results[0].result)
{
case RESULT_ACCEPT:
conn->assoc_group_id = response_hdr->bind_ack.assoc_gid;
conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
conn->ActiveInterface = *InterfaceId;
break;
case RESULT_PROVIDER_REJECTION:
switch (results->results[0].reason)
{
case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
ERR("syntax %s, %d.%d not supported\n",
debugstr_guid(&InterfaceId->SyntaxGUID),
InterfaceId->SyntaxVersion.MajorVersion,
InterfaceId->SyntaxVersion.MinorVersion);
status = RPC_S_UNKNOWN_IF;
break;
case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
ERR("transfer syntax not supported\n");
status = RPC_S_SERVER_UNAVAILABLE;
break;
case REASON_NONE:
default:
status = RPC_S_CALL_FAILED_DNE;
}
break;
case RESULT_USER_REJECTION:
default:
ERR("rejection result %d\n", results->results[0].result);
status = RPC_S_CALL_FAILED_DNE;
}
}
else
{
ERR("incorrect results size\n");
status = RPC_S_CALL_FAILED_DNE;
}
}
else
{
ERR("bind ack packet too small (%d)\n", msg.BufferLength);
status = RPC_S_PROTOCOL_ERROR;
}
break;
}
case PKT_BIND_NACK:
switch (response_hdr->bind_nack.reject_reason)
{
case REJECT_LOCAL_LIMIT_EXCEEDED:
case REJECT_TEMPORARY_CONGESTION:
ERR("server too busy\n");
status = RPC_S_SERVER_TOO_BUSY;
break;
case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED:
ERR("protocol version not supported\n");
status = RPC_S_PROTOCOL_ERROR;
break;
case REJECT_UNKNOWN_AUTHN_SERVICE:
ERR("unknown authentication service\n");
status = RPC_S_UNKNOWN_AUTHN_SERVICE;
break;
case REJECT_INVALID_CHECKSUM:
ERR("invalid checksum\n");
status = ERROR_ACCESS_DENIED;
break;
default:
ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason);
status = RPC_S_CALL_FAILED_DNE;
}
break;
default:
ERR("wrong packet type received %d\n", response_hdr->common.ptype);
status = RPC_S_PROTOCOL_ERROR;
break;
}
I_RpcFreeBuffer(&msg);
RPCRT4_FreeHeader(response_hdr);
return status;
}
static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
const RPC_SYNTAX_IDENTIFIER *InterfaceId,
const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
const RpcQualityOfService *QOS)
{
RpcConnection *Connection;
EnterCriticalSection(&assoc->cs);
/* try to find a compatible connection from the connection pool */
LIST_FOR_EACH_ENTRY(Connection, &assoc->free_connection_pool, RpcConnection, conn_pool_entry)
{
if (!memcmp(&Connection->ActiveInterface, InterfaceId,
sizeof(RPC_SYNTAX_IDENTIFIER)) &&
RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) &&
RpcQualityOfService_IsEqual(Connection->QOS, QOS))
{
list_remove(&Connection->conn_pool_entry);
LeaveCriticalSection(&assoc->cs);
TRACE("got connection from pool %p\n", Connection);
return Connection;
}
}
LeaveCriticalSection(&assoc->cs);
return NULL;
}
RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc,
const RPC_SYNTAX_IDENTIFIER *InterfaceId,
const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo,
RpcQualityOfService *QOS, RpcConnection **Connection)
{
RpcConnection *NewConnection;
RPC_STATUS status;
*Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS);
if (*Connection)
return RPC_S_OK;
/* create a new connection */
status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */,
assoc->Protseq, assoc->NetworkAddr,
assoc->Endpoint, assoc->NetworkOptions,
AuthInfo, QOS);
if (status != RPC_S_OK)
return status;
status = RPCRT4_OpenClientConnection(NewConnection);
if (status != RPC_S_OK)
{
RPCRT4_DestroyConnection(NewConnection);
return status;
}
status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax);
if (status != RPC_S_OK)
{
RPCRT4_DestroyConnection(NewConnection);
return status;
}
*Connection = NewConnection;
return RPC_S_OK;
}
void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
{
assert(!Connection->server);
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);
LeaveCriticalSection(&assoc->cs);
}
RPC_STATUS RpcServerAssoc_AllocateContextHandle(RpcAssoc *assoc, void *CtxGuard,
NDR_SCONTEXT *SContext)
{
RpcContextHandle *context_handle;
context_handle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*context_handle));
if (!context_handle)
return ERROR_OUTOFMEMORY;
context_handle->ctx_guard = CtxGuard;
RtlInitializeResource(&context_handle->rw_lock);
context_handle->refs = 1;
/* lock here to mirror unmarshall, so we don't need to special-case the
* freeing of a non-marshalled context handle */
RtlAcquireResourceExclusive(&context_handle->rw_lock, TRUE);
EnterCriticalSection(&assoc->cs);
list_add_tail(&assoc->context_handle_list, &context_handle->entry);
LeaveCriticalSection(&assoc->cs);
*SContext = (NDR_SCONTEXT)context_handle;
return RPC_S_OK;
}
BOOL RpcContextHandle_IsGuardCorrect(NDR_SCONTEXT SContext, void *CtxGuard)
{
RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
return context_handle->ctx_guard == CtxGuard;
}
RPC_STATUS RpcServerAssoc_FindContextHandle(RpcAssoc *assoc, const UUID *uuid,
void *CtxGuard, ULONG Flags, NDR_SCONTEXT *SContext)
{
RpcContextHandle *context_handle;
EnterCriticalSection(&assoc->cs);
LIST_FOR_EACH_ENTRY(context_handle, &assoc->context_handle_list, RpcContextHandle, entry)
{
if (RpcContextHandle_IsGuardCorrect((NDR_SCONTEXT)context_handle, CtxGuard) &&
!memcmp(&context_handle->uuid, uuid, sizeof(*uuid)))
{
*SContext = (NDR_SCONTEXT)context_handle;
if (context_handle->refs++)
{
LeaveCriticalSection(&assoc->cs);
TRACE("found %p\n", context_handle);
RtlAcquireResourceExclusive(&context_handle->rw_lock, TRUE);
return RPC_S_OK;
}
}
}
LeaveCriticalSection(&assoc->cs);
ERR("no context handle found for uuid %s, guard %p\n",
debugstr_guid(uuid), CtxGuard);
return ERROR_INVALID_HANDLE;
}
RPC_STATUS RpcServerAssoc_UpdateContextHandle(RpcAssoc *assoc,
NDR_SCONTEXT SContext,
void *CtxGuard,
NDR_RUNDOWN rundown_routine)
{
RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
RPC_STATUS status;
if (!RpcContextHandle_IsGuardCorrect((NDR_SCONTEXT)context_handle, CtxGuard))
return ERROR_INVALID_HANDLE;
EnterCriticalSection(&assoc->cs);
if (UuidIsNil(&context_handle->uuid, &status))
{
/* add a ref for the data being valid */
context_handle->refs++;
UuidCreate(&context_handle->uuid);
context_handle->rundown_routine = rundown_routine;
TRACE("allocated uuid %s for context handle %p\n",
debugstr_guid(&context_handle->uuid), context_handle);
}
LeaveCriticalSection(&assoc->cs);
return RPC_S_OK;
}
void RpcContextHandle_GetUuid(NDR_SCONTEXT SContext, UUID *uuid)
{
RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
*uuid = context_handle->uuid;
}
static void RpcContextHandle_Destroy(RpcContextHandle *context_handle)
{
TRACE("freeing %p\n", context_handle);
if (context_handle->user_context && context_handle->rundown_routine)
{
TRACE("calling rundown routine %p with user context %p\n",
context_handle->rundown_routine, context_handle->user_context);
context_handle->rundown_routine(context_handle->user_context);
}
RtlDeleteResource(&context_handle->rw_lock);
HeapFree(GetProcessHeap(), 0, context_handle);
}
unsigned int RpcServerAssoc_ReleaseContextHandle(RpcAssoc *assoc, NDR_SCONTEXT SContext, BOOL release_lock)
{
RpcContextHandle *context_handle = (RpcContextHandle *)SContext;
unsigned int refs;
if (release_lock)
RtlReleaseResource(&context_handle->rw_lock);
EnterCriticalSection(&assoc->cs);
refs = --context_handle->refs;
if (!refs)
list_remove(&context_handle->entry);
LeaveCriticalSection(&assoc->cs);
if (!refs)
RpcContextHandle_Destroy(context_handle);
return refs;
}

View file

@ -0,0 +1,58 @@
/*
* Associations
*
* Copyright 2007 Robert Shearman (for CodeWeavers)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include "rpc_binding.h"
#include "wine/list.h"
typedef struct _RpcAssoc
{
struct list entry; /* entry in the global list of associations */
LONG refs;
LPSTR Protseq;
LPSTR NetworkAddr;
LPSTR Endpoint;
LPWSTR NetworkOptions;
/* id of this association group */
ULONG assoc_group_id;
CRITICAL_SECTION cs;
/* client-only */
/* connections available to be used (protected by cs) */
struct list free_connection_pool;
/* server-only */
struct list context_handle_list; /* protected by cs */
} RpcAssoc;
RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc);
RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, RpcConnection **Connection);
void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection);
ULONG RpcAssoc_Release(RpcAssoc *assoc);
RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, unsigned long assoc_gid, RpcAssoc **assoc_out);
RPC_STATUS RpcServerAssoc_AllocateContextHandle(RpcAssoc *assoc, void *CtxGuard, NDR_SCONTEXT *SContext);
RPC_STATUS RpcServerAssoc_FindContextHandle(RpcAssoc *assoc, const UUID *uuid, void *CtxGuard, ULONG Flags, NDR_SCONTEXT *SContext);
RPC_STATUS RpcServerAssoc_UpdateContextHandle(RpcAssoc *assoc, NDR_SCONTEXT SContext, void *CtxGuard, NDR_RUNDOWN rundown_routine);
unsigned int RpcServerAssoc_ReleaseContextHandle(RpcAssoc *assoc, NDR_SCONTEXT SContext, BOOL release_lock);
void RpcContextHandle_GetUuid(NDR_SCONTEXT SContext, UUID *uuid);
BOOL RpcContextHandle_IsGuardCorrect(NDR_SCONTEXT SContext, void *CtxGuard);

View file

@ -39,7 +39,7 @@
#include "wine/debug.h"
#include "rpc_binding.h"
#include "rpc_message.h"
#include "rpc_assoc.h"
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
@ -1001,7 +1001,7 @@ ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo)
{
HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User);
HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain);
HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User);
HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Password);
HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity);
}
HeapFree(GetProcessHeap(), 0, AuthInfo);

View file

@ -22,6 +22,7 @@
#define __WINE_RPC_BINDING_H
#include "wine/rpcss_shared.h"
#include "rpcndr.h"
#include "security.h"
#include "wine/list.h"
@ -49,37 +50,16 @@ typedef struct _RpcQualityOfService
RPC_SECURITY_QOS_V2_W *qos;
} RpcQualityOfService;
typedef struct _RpcAssoc
{
struct list entry; /* entry in the global list of associations */
LONG refs;
LPSTR Protseq;
LPSTR NetworkAddr;
LPSTR Endpoint;
LPWSTR NetworkOptions;
/* id of this association group */
ULONG assoc_group_id;
CRITICAL_SECTION cs;
struct list connection_pool;
} RpcAssoc;
struct connection_ops;
typedef struct _RpcConnection
{
struct _RpcConnection* Next;
BOOL server;
LPSTR NetworkAddr;
LPSTR Endpoint;
LPWSTR NetworkOptions;
const struct connection_ops *ops;
USHORT MaxTransmissionSize;
/* The active interface bound to server. */
RPC_SYNTAX_IDENTIFIER ActiveInterface;
USHORT NextCallId;
/* authentication */
CtxtHandle ctx;
@ -93,6 +73,13 @@ typedef struct _RpcConnection
/* client-only */
struct list conn_pool_entry;
ULONG assoc_group_id; /* association group returned during binding */
/* server-only */
/* The active interface bound to server. */
RPC_SYNTAX_IDENTIFIER ActiveInterface;
USHORT NextCallId;
struct _RpcConnection* Next;
struct _RpcBinding *server_binding;
} RpcConnection;
struct connection_ops {
@ -104,6 +91,7 @@ struct connection_ops {
int (*read)(RpcConnection *conn, void *buffer, unsigned int len);
int (*write)(RpcConnection *conn, const void *buffer, unsigned int len);
int (*close)(RpcConnection *conn);
void (*cancel_call)(RpcConnection *conn);
size_t (*get_top_of_tower)(unsigned char *tower_data, const char *networkaddr, const char *endpoint);
RPC_STATUS (*parse_top_of_tower)(const unsigned char *tower_data, size_t tower_size, char **networkaddr, char **endpoint);
};
@ -122,7 +110,7 @@ typedef struct _RpcBinding
RPC_BLOCKING_FN BlockingFn;
ULONG ServerTid;
RpcConnection* FromConn;
RpcAssoc *Assoc;
struct _RpcAssoc *Assoc;
/* authentication */
RpcAuthInfo *AuthInfo;
@ -145,11 +133,6 @@ ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos);
ULONG RpcQualityOfService_Release(RpcQualityOfService *qos);
BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2);
RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc);
RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, RpcConnection **Connection);
void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection);
ULONG RpcAssoc_Release(RpcAssoc *assoc);
RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS);
RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection);
RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection);
@ -190,6 +173,11 @@ static inline int rpcrt4_conn_close(RpcConnection *Connection)
return Connection->ops->close(Connection);
}
static inline void rpcrt4_conn_cancel_call(RpcConnection *Connection)
{
Connection->ops->cancel_call(Connection);
}
static inline RPC_STATUS rpcrt4_conn_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
{
return old_conn->ops->handoff(old_conn, new_conn);
@ -199,4 +187,11 @@ static inline RPC_STATUS rpcrt4_conn_handoff(RpcConnection *old_conn, RpcConnect
RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, size_t *tower_size, const char *protseq, const char *networkaddr, const char *endpoint);
RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, size_t tower_size, char **protseq, char **networkaddr, char **endpoint);
void RPCRT4_SetThreadCurrentConnection(RpcConnection *Connection);
void RPCRT4_SetThreadCurrentCallHandle(RpcBinding *Binding);
RpcBinding *RPCRT4_GetThreadCurrentCallHandle(void);
void RPCRT4_PushThreadContextHandle(NDR_SCONTEXT SContext);
void RPCRT4_RemoveThreadContextHandle(NDR_SCONTEXT SContext);
NDR_SCONTEXT RPCRT4_PopThreadContextHandle(void);
#endif

View file

@ -241,6 +241,7 @@ RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation,
RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation,
unsigned short MaxTransmissionSize,
unsigned short MaxReceiveSize,
unsigned long AssocGroupId,
LPCSTR ServerAddress,
unsigned long Result,
unsigned long Reason,
@ -266,6 +267,7 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation,
header->common.frag_len = header_size;
header->bind_ack.max_tsize = MaxTransmissionSize;
header->bind_ack.max_rsize = MaxReceiveSize;
header->bind_ack.assoc_gid = AssocGroupId;
server_address = (RpcAddressString*)(&header->bind_ack + 1);
server_address->length = strlen(ServerAddress) + 1;
strcpy(server_address->string, ServerAddress);
@ -415,7 +417,7 @@ static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection,
sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0);
if (sec_status != SEC_E_OK)
{
ERR("EncryptMessage failed with 0x%08x\n", sec_status);
ERR("DecryptMessage failed with 0x%08x\n", sec_status);
return RPC_S_SEC_PKG_ERROR;
}
}
@ -449,6 +451,8 @@ static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header,
LONG alen;
RPC_STATUS status;
RPCRT4_SetThreadCurrentConnection(Connection);
buffer_pos = Buffer;
/* The packet building functions save the packet header size, so we can use it. */
hdr_size = Header->common.frag_len;
@ -518,6 +522,7 @@ static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header,
if (status != RPC_S_OK)
{
HeapFree(GetProcessHeap(), 0, pkt);
RPCRT4_SetThreadCurrentConnection(NULL);
return status;
}
}
@ -528,7 +533,8 @@ write:
HeapFree(GetProcessHeap(), 0, pkt);
if (count<0) {
WARN("rpcrt4_conn_write failed (auth)\n");
return RPC_S_PROTOCOL_ERROR;
RPCRT4_SetThreadCurrentConnection(NULL);
return RPC_S_CALL_FAILED;
}
buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len;
@ -536,6 +542,7 @@ write:
Header->common.flags &= ~RPC_FLG_FIRST;
}
RPCRT4_SetThreadCurrentConnection(NULL);
return RPC_S_OK;
}
@ -697,11 +704,13 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
TRACE("(%p, %p, %p)\n", Connection, Header, pMsg);
RPCRT4_SetThreadCurrentConnection(Connection);
/* read packet common header */
dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr));
if (dwRead != sizeof(common_hdr)) {
WARN("Short read of header, %d bytes\n", dwRead);
status = RPC_S_PROTOCOL_ERROR;
status = RPC_S_CALL_FAILED;
goto fail;
}
@ -727,7 +736,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
if (dwRead != hdr_length - sizeof(common_hdr)) {
WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
status = RPC_S_PROTOCOL_ERROR;
status = RPC_S_CALL_FAILED;
goto fail;
}
@ -753,7 +762,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
if (auth_length) {
auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&common_hdr));
if (!auth_data) {
status = RPC_S_PROTOCOL_ERROR;
status = RPC_S_OUT_OF_RESOURCES;
goto fail;
}
}
@ -799,7 +808,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
(unsigned char *)pMsg->Buffer + buffer_length, data_length);
if (dwRead != data_length) {
WARN("bad data length, %d/%ld\n", dwRead, data_length);
status = RPC_S_PROTOCOL_ERROR;
status = RPC_S_CALL_FAILED;
goto fail;
}
@ -819,7 +828,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
if (dwRead != header_auth_len) {
WARN("bad authentication data length, %d/%d\n", dwRead,
header_auth_len);
status = RPC_S_PROTOCOL_ERROR;
status = RPC_S_CALL_FAILED;
goto fail;
}
@ -828,12 +837,15 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
if ((common_hdr.ptype != PKT_BIND) &&
(common_hdr.ptype != PKT_BIND_ACK) &&
(common_hdr.ptype != PKT_AUTH3))
{
status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE,
*Header, hdr_length,
(unsigned char *)pMsg->Buffer + buffer_length, data_length,
(RpcAuthVerifier *)auth_data,
(unsigned char *)auth_data + sizeof(RpcAuthVerifier),
header_auth_len - sizeof(RpcAuthVerifier));
if (status != RPC_S_OK) goto fail;
}
}
buffer_length += data_length;
@ -844,7 +856,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
dwRead = rpcrt4_conn_read(Connection, *Header, hdr_length);
if (dwRead != hdr_length) {
WARN("invalid packet header size (%d)\n", dwRead);
status = RPC_S_PROTOCOL_ERROR;
status = RPC_S_CALL_FAILED;
goto fail;
}
@ -869,6 +881,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
status = RPC_S_OK;
fail:
RPCRT4_SetThreadCurrentConnection(NULL);
if (status != RPC_S_OK) {
RPCRT4_FreeHeader(*Header);
*Header = NULL;

View file

@ -30,7 +30,7 @@ RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_STATUS
RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, unsigned long BufferLength);
RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, unsigned long AssocGroupId, const RPC_SYNTAX_IDENTIFIER *AbstractId, const RPC_SYNTAX_IDENTIFIER *TransferId);
RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor);
RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, LPCSTR ServerAddress, unsigned long Result, unsigned long Reason, const RPC_SYNTAX_IDENTIFIER *TransferId);
RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, unsigned long AssocGroupId, LPCSTR ServerAddress, unsigned long Result, unsigned long Reason, const RPC_SYNTAX_IDENTIFIER *TransferId);
VOID RPCRT4_FreeHeader(RpcPktHdr *Header);
RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength);
RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg);

View file

@ -42,6 +42,7 @@
#include "wine/exception.h"
#include "rpc_server.h"
#include "rpc_assoc.h"
#include "rpc_message.h"
#include "rpc_defs.h"
#include "ncastatus.h"
@ -167,10 +168,13 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
RpcServerInterface* sif;
RPC_DISPATCH_FUNCTION func;
UUID *object_uuid;
RpcPktHdr *response;
RpcPktHdr *response = NULL;
void *buf = msg->Buffer;
RPC_STATUS status;
BOOL exception;
NDR_SCONTEXT context_handle;
msg->Handle = (RPC_BINDING_HANDLE)conn->server_binding;
switch (hdr->common.ptype) {
case PKT_BIND:
@ -178,11 +182,21 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
/* FIXME: do more checks! */
if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE ||
!UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
!UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) ||
conn->server_binding) {
TRACE("packet size less than min size, or active interface syntax guid non-null\n");
sif = NULL;
} else {
/* create temporary binding */
if (RPCRT4_MakeBinding(&conn->server_binding, conn) == RPC_S_OK &&
RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(conn),
conn->NetworkAddr, conn->Endpoint,
conn->NetworkOptions,
hdr->bind.assoc_gid,
&conn->server_binding->Assoc) == RPC_S_OK)
sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE);
else
sif = NULL;
}
if (sif == NULL) {
TRACE("rejecting bind request on connection %p\n", conn);
@ -197,6 +211,7 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
RPC_MAX_PACKET_SIZE,
RPC_MAX_PACKET_SIZE,
conn->server_binding->Assoc->assoc_group_id,
conn->Endpoint,
RESULT_ACCEPT, REASON_NONE,
&sif->If->TransferSyntax);
@ -279,6 +294,7 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
exception = FALSE;
/* dispatch */
RPCRT4_SetThreadCurrentCallHandle(msg->Handle);
__TRY {
if (func) func(msg);
} __EXCEPT(rpc_filter) {
@ -290,6 +306,11 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA
response = RPCRT4_BuildFaultHeader(msg->DataRepresentation,
RPC2NCA_STATUS(status));
} __ENDTRY
RPCRT4_SetThreadCurrentCallHandle(NULL);
/* release any unmarshalled context handles */
while ((context_handle = RPCRT4_PopThreadContextHandle()) != NULL)
RpcServerAssoc_ReleaseContextHandle(conn->server_binding->Assoc, context_handle, TRUE);
if (!exception)
response = RPCRT4_BuildResponseHeader(msg->DataRepresentation,
@ -318,7 +339,6 @@ fail:
if (msg->Buffer == buf) msg->Buffer = NULL;
TRACE("freeing Buffer=%p\n", buf);
HeapFree(GetProcessHeap(), 0, buf);
RPCRT4_DestroyBinding(msg->Handle);
msg->Handle = 0;
I_RpcFreeBuffer(msg);
msg->Buffer = NULL;
@ -338,7 +358,6 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
{
RpcConnection* conn = (RpcConnection*)the_arg;
RpcPktHdr *hdr;
RpcBinding *pbind;
RPC_MESSAGE *msg;
RPC_STATUS status;
RpcPacket *packet;
@ -348,11 +367,6 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
for (;;) {
msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
/* create temporary binding for dispatch, it will be freed in
* RPCRT4_process_packet */
RPCRT4_MakeBinding(&pbind, conn);
msg->Handle = (RPC_BINDING_HANDLE)pbind;
status = RPCRT4_Receive(conn, &hdr, msg);
if (status != RPC_S_OK) {
WARN("receive failed with error %lx\n", status);
@ -1114,3 +1128,12 @@ RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize)
FIXME("(0x%x): stub\n", ThreadStackSize);
return RPC_S_OK;
}
/***********************************************************************
* I_RpcGetCurrentCallHandle (RPCRT4.@)
*/
RPC_BINDING_HANDLE WINAPI I_RpcGetCurrentCallHandle(void)
{
TRACE("\n");
return RPCRT4_GetThreadCurrentCallHandle();
}

View file

@ -84,17 +84,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(rpc);
static CRITICAL_SECTION assoc_list_cs;
static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
{
0, 0, &assoc_list_cs,
{ &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }
};
static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
static struct list assoc_list = LIST_INIT(assoc_list);
/**** ncacn_np support ****/
typedef struct _RpcConnection_np
@ -144,7 +133,7 @@ static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pnam
RpcConnection_np *npc = (RpcConnection_np *) Connection;
TRACE("listening on %s\n", pname);
npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
PIPE_UNLIMITED_INSTANCES,
RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
@ -421,6 +410,11 @@ static int rpcrt4_conn_np_close(RpcConnection *Connection)
return 0;
}
static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
{
/* FIXME: implement when named pipe writes use overlapped I/O */
}
static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
const char *networkaddr,
const char *endpoint)
@ -605,7 +599,15 @@ static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq,
if (!objs)
return -1;
res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
do
{
/* an alertable wait isn't strictly necessary, but due to our
* overlapped I/O implementation in Wine we need to free some memory
* by the file user APC being called, even if no completion routine was
* specified at the time of starting the async operation */
res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
} while (res == WAIT_IO_COMPLETION);
if (res == WAIT_OBJECT_0)
return 0;
else if (res == WAIT_FAILED)
@ -708,6 +710,7 @@ typedef struct _RpcConnection_tcp
{
RpcConnection common;
int sock;
int cancel_fds[2];
} RpcConnection_tcp;
static RpcConnection *rpcrt4_conn_tcp_alloc(void)
@ -717,6 +720,14 @@ static RpcConnection *rpcrt4_conn_tcp_alloc(void)
if (tcpc == NULL)
return NULL;
tcpc->sock = -1;
#ifndef __REACTOS__
if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
{
ERR("socketpair() failed: %s\n", strerror(errno));
HeapFree(GetProcessHeap(), 0, tcpc);
return NULL;
}
#endif
return &tcpc->common;
}
@ -766,7 +777,7 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
}
sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
if (sock < 0)
if (sock == -1)
{
WARN("socket() failed: %s\n", strerror(errno));
continue;
@ -803,8 +814,8 @@ static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *pr
struct addrinfo *ai;
struct addrinfo *ai_cur;
struct addrinfo hints;
RpcConnection *first_connection = NULL;
u_long blocking;
RpcConnection *first_connection = NULL;
TRACE("(%p, %s)\n", protseq, endpoint);
@ -843,7 +854,7 @@ static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *pr
}
sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
if (sock < 0)
if (sock == -1)
{
WARN("socket() failed: %s\n", strerror(errno));
status = RPC_S_CANT_CREATE_ENDPOINT;
@ -951,18 +962,69 @@ static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
void *buffer, unsigned int count)
{
RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
return r;
int bytes_read = 0;
do
{
int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
if (!r)
return -1;
else if (r > 0)
bytes_read += r;
else if (errno != EAGAIN)
{
WARN("recv() failed: %s\n", strerror(errno));
return -1;
}
else
{
struct pollfd pfds[2];
pfds[0].fd = tcpc->sock;
pfds[0].events = POLLIN;
pfds[1].fd = tcpc->cancel_fds[0];
pfds[1].events = POLLIN;
if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
{
ERR("poll() failed: %s\n", strerror(errno));
return -1;
}
if (pfds[1].revents & POLLIN) /* canceled */
{
char dummy;
read(pfds[1].fd, &dummy, sizeof(dummy));
return -1;
}
}
} while (bytes_read != count);
TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
return bytes_read;
}
static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
const void *buffer, unsigned int count)
{
RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
int r = write(tcpc->sock, buffer, count);
TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
return r;
int bytes_written = 0;
do
{
int r = write(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written);
if (r >= 0)
bytes_written += r;
else if (errno != EAGAIN)
return -1;
else
{
struct pollfd pfd;
pfd.fd = tcpc->sock;
pfd.events = POLLOUT;
if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
{
ERR("poll() failed: %s\n", strerror(errno));
return -1;
}
}
} while (bytes_written != count);
TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
return bytes_written;
}
static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
@ -974,9 +1036,21 @@ static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
if (tcpc->sock != -1)
close(tcpc->sock);
tcpc->sock = -1;
close(tcpc->cancel_fds[0]);
close(tcpc->cancel_fds[1]);
return 0;
}
static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
{
RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
char dummy = 1;
TRACE("%p\n", Connection);
write(tcpc->cancel_fds[1], &dummy, 1);
}
static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
const char *networkaddr,
const char *endpoint)
@ -1261,6 +1335,7 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_conn_np_read,
rpcrt4_conn_np_write,
rpcrt4_conn_np_close,
rpcrt4_conn_np_cancel_call,
rpcrt4_ncacn_np_get_top_of_tower,
rpcrt4_ncacn_np_parse_top_of_tower,
},
@ -1272,6 +1347,7 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_conn_np_read,
rpcrt4_conn_np_write,
rpcrt4_conn_np_close,
rpcrt4_conn_np_cancel_call,
rpcrt4_ncalrpc_get_top_of_tower,
rpcrt4_ncalrpc_parse_top_of_tower,
},
@ -1283,6 +1359,7 @@ static const struct connection_ops conn_protseq_list[] = {
rpcrt4_conn_tcp_read,
rpcrt4_conn_tcp_write,
rpcrt4_conn_tcp_close,
rpcrt4_conn_tcp_cancel_call,
rpcrt4_ncacn_ip_tcp_get_top_of_tower,
rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
}
@ -1378,6 +1455,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
NewConnection = ops->alloc();
NewConnection->Next = NULL;
NewConnection->server_binding = NULL;
NewConnection->server = server;
NewConnection->ops = ops;
NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
@ -1405,283 +1483,6 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
return RPC_S_OK;
}
RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
LPCSTR Endpoint, LPCWSTR NetworkOptions,
RpcAssoc **assoc_out)
{
RpcAssoc *assoc;
EnterCriticalSection(&assoc_list_cs);
LIST_FOR_EACH_ENTRY(assoc, &assoc_list, RpcAssoc, entry)
{
if (!strcmp(Protseq, assoc->Protseq) &&
!strcmp(NetworkAddr, assoc->NetworkAddr) &&
!strcmp(Endpoint, assoc->Endpoint) &&
((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions)))
{
assoc->refs++;
*assoc_out = assoc;
LeaveCriticalSection(&assoc_list_cs);
TRACE("using existing assoc %p\n", assoc);
return RPC_S_OK;
}
}
assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
if (!assoc)
{
LeaveCriticalSection(&assoc_list_cs);
return RPC_S_OUT_OF_RESOURCES;
}
assoc->refs = 1;
list_init(&assoc->connection_pool);
InitializeCriticalSection(&assoc->cs);
assoc->Protseq = RPCRT4_strdupA(Protseq);
assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
assoc->Endpoint = RPCRT4_strdupA(Endpoint);
assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL;
assoc->assoc_group_id = 0;
list_add_head(&assoc_list, &assoc->entry);
*assoc_out = assoc;
LeaveCriticalSection(&assoc_list_cs);
TRACE("new assoc %p\n", assoc);
return RPC_S_OK;
}
ULONG RpcAssoc_Release(RpcAssoc *assoc)
{
ULONG refs;
EnterCriticalSection(&assoc_list_cs);
refs = --assoc->refs;
if (!refs)
list_remove(&assoc->entry);
LeaveCriticalSection(&assoc_list_cs);
if (!refs)
{
RpcConnection *Connection, *cursor2;
TRACE("destroying assoc %p\n", assoc);
LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->connection_pool, RpcConnection, conn_pool_entry)
{
list_remove(&Connection->conn_pool_entry);
RPCRT4_DestroyConnection(Connection);
}
HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions);
HeapFree(GetProcessHeap(), 0, assoc->Endpoint);
HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr);
HeapFree(GetProcessHeap(), 0, assoc->Protseq);
HeapFree(GetProcessHeap(), 0, assoc);
}
return refs;
}
#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn,
const RPC_SYNTAX_IDENTIFIER *InterfaceId,
const RPC_SYNTAX_IDENTIFIER *TransferSyntax)
{
RpcPktHdr *hdr;
RpcPktHdr *response_hdr;
RPC_MESSAGE msg;
RPC_STATUS status;
TRACE("sending bind request to server\n");
hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
assoc->assoc_group_id,
InterfaceId, TransferSyntax);
status = RPCRT4_Send(conn, hdr, NULL, 0);
RPCRT4_FreeHeader(hdr);
if (status != RPC_S_OK)
return status;
status = RPCRT4_Receive(conn, &response_hdr, &msg);
if (status != RPC_S_OK)
{
ERR("receive failed\n");
return status;
}
switch (response_hdr->common.ptype)
{
case PKT_BIND_ACK:
{
RpcAddressString *server_address = msg.Buffer;
if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) ||
(msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)))
{
unsigned short remaining = msg.BufferLength -
ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4);
RpcResults *results = (RpcResults*)((ULONG_PTR)server_address +
ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
if ((results->num_results == 1) && (remaining >= sizeof(*results)))
{
switch (results->results[0].result)
{
case RESULT_ACCEPT:
conn->assoc_group_id = response_hdr->bind_ack.assoc_gid;
conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
conn->ActiveInterface = *InterfaceId;
break;
case RESULT_PROVIDER_REJECTION:
switch (results->results[0].reason)
{
case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
ERR("syntax %s, %d.%d not supported\n",
debugstr_guid(&InterfaceId->SyntaxGUID),
InterfaceId->SyntaxVersion.MajorVersion,
InterfaceId->SyntaxVersion.MinorVersion);
status = RPC_S_UNKNOWN_IF;
break;
case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
ERR("transfer syntax not supported\n");
status = RPC_S_SERVER_UNAVAILABLE;
break;
case REASON_NONE:
default:
status = RPC_S_CALL_FAILED_DNE;
}
break;
case RESULT_USER_REJECTION:
default:
ERR("rejection result %d\n", results->results[0].result);
status = RPC_S_CALL_FAILED_DNE;
}
}
else
{
ERR("incorrect results size\n");
status = RPC_S_CALL_FAILED_DNE;
}
}
else
{
ERR("bind ack packet too small (%d)\n", msg.BufferLength);
status = RPC_S_PROTOCOL_ERROR;
}
break;
}
case PKT_BIND_NACK:
switch (response_hdr->bind_nack.reject_reason)
{
case REJECT_LOCAL_LIMIT_EXCEEDED:
case REJECT_TEMPORARY_CONGESTION:
ERR("server too busy\n");
status = RPC_S_SERVER_TOO_BUSY;
break;
case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED:
ERR("protocol version not supported\n");
status = RPC_S_PROTOCOL_ERROR;
break;
case REJECT_UNKNOWN_AUTHN_SERVICE:
ERR("unknown authentication service\n");
status = RPC_S_UNKNOWN_AUTHN_SERVICE;
break;
case REJECT_INVALID_CHECKSUM:
ERR("invalid checksum\n");
status = ERROR_ACCESS_DENIED;
break;
default:
ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason);
status = RPC_S_CALL_FAILED_DNE;
}
break;
default:
ERR("wrong packet type received %d\n", response_hdr->common.ptype);
status = RPC_S_PROTOCOL_ERROR;
break;
}
RPCRT4_FreeHeader(response_hdr);
return status;
}
static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
const RPC_SYNTAX_IDENTIFIER *InterfaceId,
const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
const RpcQualityOfService *QOS)
{
RpcConnection *Connection;
EnterCriticalSection(&assoc->cs);
/* try to find a compatible connection from the connection pool */
LIST_FOR_EACH_ENTRY(Connection, &assoc->connection_pool, RpcConnection, conn_pool_entry)
{
if (!memcmp(&Connection->ActiveInterface, InterfaceId,
sizeof(RPC_SYNTAX_IDENTIFIER)) &&
RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) &&
RpcQualityOfService_IsEqual(Connection->QOS, QOS))
{
list_remove(&Connection->conn_pool_entry);
LeaveCriticalSection(&assoc->cs);
TRACE("got connection from pool %p\n", Connection);
return Connection;
}
}
LeaveCriticalSection(&assoc->cs);
return NULL;
}
RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc,
const RPC_SYNTAX_IDENTIFIER *InterfaceId,
const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo,
RpcQualityOfService *QOS, RpcConnection **Connection)
{
RpcConnection *NewConnection;
RPC_STATUS status;
*Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS);
if (*Connection)
return RPC_S_OK;
/* create a new connection */
status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */,
assoc->Protseq, assoc->NetworkAddr,
assoc->Endpoint, assoc->NetworkOptions,
AuthInfo, QOS);
if (status != RPC_S_OK)
return status;
status = RPCRT4_OpenClientConnection(NewConnection);
if (status != RPC_S_OK)
{
RPCRT4_DestroyConnection(NewConnection);
return status;
}
status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax);
if (status != RPC_S_OK)
{
RPCRT4_DestroyConnection(NewConnection);
return status;
}
*Connection = NewConnection;
return RPC_S_OK;
}
void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
{
assert(!Connection->server);
EnterCriticalSection(&assoc->cs);
if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id;
list_add_head(&assoc->connection_pool, &Connection->conn_pool_entry);
LeaveCriticalSection(&assoc->cs);
}
RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
{
@ -1707,6 +1508,10 @@ RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
/* server-only */
if (Connection->server_binding) RPCRT4_DestroyBinding(Connection->server_binding);
HeapFree(GetProcessHeap(), 0, Connection);
return RPC_S_OK;
}

View file

@ -23,11 +23,13 @@
<file>cproxy.c</file>
<file>cpsf.c</file>
<file>cstub.c</file>
<file>ndr_contexthandle.c</file>
<file>ndr_clientserver.c</file>
<file>ndr_fullpointer.c</file>
<file>ndr_marshall.c</file>
<file>ndr_ole.c</file>
<file>ndr_stubless.c</file>
<file>rpc_assoc.c</file>
<file>rpc_binding.c</file>
<file>rpc_epmap.c</file>
<file>rpc_message.c</file>

View file

@ -51,7 +51,7 @@
@ stub I_RpcGetAssociationContext
@ stdcall I_RpcGetBuffer(ptr)
@ stub I_RpcGetBufferWithObject
@ stub I_RpcGetCurrentCallHandle
@ stdcall I_RpcGetCurrentCallHandle()
@ stub I_RpcGetExtendedError
@ stub I_RpcGetServerContextList
@ stub I_RpcGetThreadEvent # win9x
@ -294,7 +294,7 @@
@ stdcall NdrProxyGetBuffer(ptr ptr)
@ stdcall NdrProxyInitialize(ptr ptr ptr ptr long)
@ stdcall NdrProxySendReceive(ptr ptr)
@ stub NdrRangeUnmarshall
@ stdcall NdrRangeUnmarshall(ptr ptr ptr long)
@ stub NdrRpcSmClientAllocate
@ stub NdrRpcSmClientFree
@ stub NdrRpcSmSetClientToOsf
@ -395,7 +395,7 @@
@ stdcall RpcBindingToStringBindingW(ptr ptr)
@ stdcall RpcBindingVectorFree(ptr)
@ stub RpcCancelAsyncCall
@ stub RpcCancelThread
@ stdcall RpcCancelThread(ptr)
@ stub RpcCancelThreadEx
@ stub RpcCertGeneratePrincipalNameA
@ stub RpcCertGeneratePrincipalNameW
@ -414,7 +414,7 @@
@ stub RpcErrorNumberOfRecords # wxp
@ stub RpcErrorResetEnumeration # wxp
@ stub RpcErrorSaveErrorInfo # wxp
@ stub RpcErrorStartEnumeration # wxp
@ stdcall RpcErrorStartEnumeration(ptr)
@ stub RpcFreeAuthorizationContext # wxp
@ stub RpcGetAsyncCallStatus
@ stub RpcIfIdVectorFree
@ -438,7 +438,7 @@
@ stub RpcMgmtInqStats
@ stdcall RpcMgmtIsServerListening(ptr)
@ stub RpcMgmtSetAuthorizationFn
@ stub RpcMgmtSetCancelTimeout
@ stdcall RpcMgmtSetCancelTimeout(long)
@ stdcall RpcMgmtSetComTimeout(ptr long)
@ stub RpcMgmtSetParameter # win9x
@ stdcall RpcMgmtSetServerStackSize(long)
@ -494,7 +494,7 @@
@ stub RpcServerYield
@ stub RpcSmAllocate
@ stub RpcSmClientFree
@ stub RpcSmDestroyClientContext
@ stdcall RpcSmDestroyClientContext(ptr)
@ stub RpcSmDisableAllocate
@ stub RpcSmEnableAllocate
@ stub RpcSmFree
@ -505,7 +505,7 @@
@ stub RpcSsAllocate
@ stub RpcSsContextLockExclusive # wxp
@ stub RpcSsContextLockShared # wxp
@ stub RpcSsDestroyClientContext
@ stdcall RpcSsDestroyClientContext(ptr)
@ stub RpcSsDisableAllocate
@ stub RpcSsDontSerializeContext
@ stub RpcSsEnableAllocate

View file

@ -100,6 +100,8 @@
#include "winerror.h"
#include "winbase.h"
#include "winuser.h"
#include "winnt.h"
#include "winternl.h"
#include "iptypes.h"
#include "iphlpapi.h"
#include "wine/unicode.h"
@ -133,6 +135,33 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
};
static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static CRITICAL_SECTION threaddata_cs;
static CRITICAL_SECTION_DEBUG threaddata_cs_debug =
{
0, 0, &threaddata_cs,
{ &threaddata_cs_debug.ProcessLocksList, &threaddata_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": threaddata_cs") }
};
static CRITICAL_SECTION threaddata_cs = { &threaddata_cs_debug, -1, 0, 0, 0, 0 };
struct list threaddata_list = LIST_INIT(threaddata_list);
struct context_handle_list
{
struct context_handle_list *next;
NDR_SCONTEXT context_handle;
};
struct threaddata
{
struct list entry;
CRITICAL_SECTION cs;
DWORD thread_id;
RpcConnection *connection;
RpcBinding *server_binding;
struct context_handle_list *context_handle_list;
};
/***********************************************************************
* DllMain
*
@ -148,14 +177,32 @@ static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
struct threaddata *tdata;
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME);
if (!master_mutex)
ERR("Failed to create master mutex\n");
break;
case DLL_THREAD_DETACH:
tdata = NtCurrentTeb()->ReservedForNtRpc;
if (tdata)
{
EnterCriticalSection(&threaddata_cs);
list_remove(&tdata->entry);
LeaveCriticalSection(&threaddata_cs);
DeleteCriticalSection(&tdata->cs);
if (tdata->connection)
ERR("tdata->connection should be NULL but is still set to %p\n", tdata->connection);
if (tdata->server_binding)
ERR("tdata->server_binding should be NULL but is still set to %p\n", tdata->server_binding);
HeapFree(GetProcessHeap(), 0, tdata);
}
break;
case DLL_PROCESS_DETACH:
CloseHandle(master_mutex);
master_mutex = NULL;
@ -202,10 +249,12 @@ RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR* String)
*
* Raises an exception.
*/
void WINAPI RpcRaiseException(RPC_STATUS exception)
void DECLSPEC_NORETURN WINAPI RpcRaiseException(RPC_STATUS exception)
{
/* FIXME: translate exception? */
/* shouldn't return */
RaiseException(exception, 0, 0, NULL);
ERR("handler continued execution\n");
ExitProcess(1);
}
/*************************************************************************
@ -823,8 +872,154 @@ void WINAPI I_RpcFree(void *Object)
/******************************************************************************
* I_RpcMapWin32Status (rpcrt4.@)
*/
DWORD WINAPI I_RpcMapWin32Status(RPC_STATUS status)
LONG WINAPI I_RpcMapWin32Status(RPC_STATUS status)
{
FIXME("(%ld): stub\n", status);
return 0;
}
/******************************************************************************
* RpcErrorStartEnumeration (rpcrt4.@)
*/
RPC_STATUS RPC_ENTRY RpcErrorStartEnumeration(RPC_ERROR_ENUM_HANDLE* EnumHandle)
{
FIXME("(%p): stub\n", EnumHandle);
return RPC_S_ENTRY_NOT_FOUND;
}
/******************************************************************************
* RpcMgmtSetCancelTimeout (rpcrt4.@)
*/
RPC_STATUS RPC_ENTRY RpcMgmtSetCancelTimeout(LONG Timeout)
{
FIXME("(%d): stub\n", Timeout);
return RPC_S_OK;
}
static struct threaddata *get_or_create_threaddata(void)
{
struct threaddata *tdata = NtCurrentTeb()->ReservedForNtRpc;
if (!tdata)
{
tdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*tdata));
if (!tdata) return NULL;
InitializeCriticalSection(&tdata->cs);
tdata->thread_id = GetCurrentThreadId();
EnterCriticalSection(&threaddata_cs);
list_add_tail(&threaddata_list, &tdata->entry);
LeaveCriticalSection(&threaddata_cs);
NtCurrentTeb()->ReservedForNtRpc = tdata;
return tdata;
}
return tdata;
}
void RPCRT4_SetThreadCurrentConnection(RpcConnection *Connection)
{
struct threaddata *tdata = get_or_create_threaddata();
if (!tdata) return;
EnterCriticalSection(&tdata->cs);
tdata->connection = Connection;
LeaveCriticalSection(&tdata->cs);
}
void RPCRT4_SetThreadCurrentCallHandle(RpcBinding *Binding)
{
struct threaddata *tdata = get_or_create_threaddata();
if (!tdata) return;
tdata->server_binding = Binding;
}
RpcBinding *RPCRT4_GetThreadCurrentCallHandle(void)
{
struct threaddata *tdata = get_or_create_threaddata();
if (!tdata) return NULL;
return tdata->server_binding;
}
void RPCRT4_PushThreadContextHandle(NDR_SCONTEXT SContext)
{
struct threaddata *tdata = get_or_create_threaddata();
struct context_handle_list *context_handle_list;
if (!tdata) return;
context_handle_list = HeapAlloc(GetProcessHeap(), 0, sizeof(*context_handle_list));
if (!context_handle_list) return;
context_handle_list->context_handle = SContext;
context_handle_list->next = tdata->context_handle_list;
tdata->context_handle_list = context_handle_list;
}
void RPCRT4_RemoveThreadContextHandle(NDR_SCONTEXT SContext)
{
struct threaddata *tdata = get_or_create_threaddata();
struct context_handle_list *current, *prev;
if (!tdata) return;
for (current = tdata->context_handle_list, prev = NULL; current; prev = current, current = current->next)
{
if (current->context_handle == SContext)
{
if (prev)
prev->next = current->next;
else
tdata->context_handle_list = current->next;
HeapFree(GetProcessHeap(), 0, current);
return;
}
}
}
NDR_SCONTEXT RPCRT4_PopThreadContextHandle(void)
{
struct threaddata *tdata = get_or_create_threaddata();
struct context_handle_list *context_handle_list;
NDR_SCONTEXT context_handle;
if (!tdata) return NULL;
context_handle_list = tdata->context_handle_list;
if (!context_handle_list) return NULL;
tdata->context_handle_list = context_handle_list->next;
context_handle = context_handle_list->context_handle;
HeapFree(GetProcessHeap(), 0, context_handle_list);
return context_handle;
}
/******************************************************************************
* RpcCancelThread (rpcrt4.@)
*/
RPC_STATUS RPC_ENTRY RpcCancelThread(void* ThreadHandle)
{
DWORD target_tid;
struct threaddata *tdata;
TRACE("(%p)\n", ThreadHandle);
target_tid = GetThreadId(ThreadHandle);
if (!target_tid)
return RPC_S_INVALID_ARG;
EnterCriticalSection(&threaddata_cs);
LIST_FOR_EACH_ENTRY(tdata, &threaddata_list, struct threaddata, entry)
if (tdata->thread_id == target_tid)
{
EnterCriticalSection(&tdata->cs);
if (tdata->connection) rpcrt4_conn_cancel_call(tdata->connection);
LeaveCriticalSection(&tdata->cs);
break;
}
LeaveCriticalSection(&threaddata_cs);
return RPC_S_OK;
}