diff --git a/reactos/dll/win32/rpcrt4/cproxy.c b/reactos/dll/win32/rpcrt4/cproxy.c index 6c26d181978..9ce555f7146 100644 --- a/reactos/dll/win32/rpcrt4/cproxy.c +++ b/reactos/dll/win32/rpcrt4/cproxy.c @@ -2,6 +2,7 @@ * COM proxy implementation * * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2009 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,6 +21,9 @@ * TODO: Handle non-i386 architectures */ +#include "config.h" +#include "wine/port.h" + #include #define COBJMACROS @@ -37,21 +41,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -struct StublessThunk; - /* I don't know what MS's std proxy structure looks like, so this probably doesn't match, but that shouldn't matter */ typedef struct { const IRpcProxyBufferVtbl *lpVtbl; LPVOID *PVtbl; LONG RefCount; - const MIDL_STUBLESS_PROXY_INFO *stubless; const IID* piid; LPUNKNOWN pUnkOuter; + IUnknown *base_object; /* must be at offset 0x10 from PVtbl */ + IRpcProxyBuffer *base_proxy; PCInterfaceName name; LPPSFACTORYBUFFER pPSFactory; LPRPCCHANNELBUFFER pChannel; - struct StublessThunk *thunks; } StdProxyImpl; static const IRpcProxyBufferVtbl StdProxy_Vtbl; @@ -62,66 +64,111 @@ static const IRpcProxyBufferVtbl StdProxy_Vtbl; #include "pshpack1.h" -struct StublessThunk { +struct thunk { BYTE push; DWORD index; - BYTE call; + BYTE jmp; LONG handler; - BYTE ret; - WORD bytes; - BYTE pad[3]; }; #include "poppack.h" -/* adjust the stack size since we don't use Windows's method */ -#define STACK_ADJUST sizeof(DWORD) +extern void call_stubless_func(void); +__ASM_GLOBAL_FUNC(call_stubless_func, + "pushl %esp\n\t" /* pointer to index */ + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + "call " __ASM_NAME("ObjectStubless") __ASM_STDCALL(4) "\n\t" + "popl %edx\n\t" /* args size */ + __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") + "movl (%esp),%ecx\n\t" /* return address */ + "addl %edx,%esp\n\t" + "jmp *%ecx" ); -#define FILL_STUBLESS(x,idx,stk) \ - x->push = 0x68; /* pushl [immediate] */ \ - x->index = (idx); \ - x->call = 0xe8; /* call [near] */ \ - x->handler = (char*)ObjectStubless - (char*)&x->ret; \ - x->ret = 0xc2; /* ret [immediate] */ \ - x->bytes = stk; \ - x->pad[0] = 0x8d; /* leal (%esi),%esi */ \ - x->pad[1] = 0x76; \ - x->pad[2] = 0x00; - -static HRESULT WINAPI ObjectStubless(DWORD index) +HRESULT WINAPI ObjectStubless(DWORD *args) { - char *args = (char*)(&index + 2); - LPVOID iface = *(LPVOID*)args; + DWORD index = args[0]; + void **iface = (void **)args[2]; + const void **vtbl = (const void **)*iface; + const MIDL_STUBLESS_PROXY_INFO *stubless = *(const MIDL_STUBLESS_PROXY_INFO **)(vtbl - 2); + const PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[index]; - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + /* store bytes to remove from stack */ + args[0] = *(const WORD*)(fs + 8); + TRACE("(%p)->(%d)([%d bytes]) ret=%08x\n", iface, index, args[0], args[1]); - PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index]; - unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; - TRACE("(%p)->(%d)([%d bytes]) ret=%08x\n", iface, index, bytes, *(DWORD*)(args+bytes)); + return NdrClientCall2(stubless->pStubDesc, fs, args + 2); +} - return NdrClientCall2(This->stubless->pStubDesc, fs, args); +#define BLOCK_SIZE 1024 +#define MAX_BLOCKS 64 /* 64k methods should be enough for anybody */ + +static const struct thunk *method_blocks[MAX_BLOCKS]; + +static const struct thunk *allocate_block( unsigned int num ) +{ + unsigned int i; + struct thunk *prev, *block; + + block = VirtualAlloc( NULL, BLOCK_SIZE * sizeof(*block), + MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); + if (!block) return NULL; + + for (i = 0; i < BLOCK_SIZE; i++) + { + block[i].push = 0x68; /* pushl */ + block[i].index = BLOCK_SIZE * num + i + 3; + block[i].jmp = 0xe9; /* jmp */ + block[i].handler = (char *)call_stubless_func - (char *)(&block[i].handler + 1); + } + VirtualProtect( block, BLOCK_SIZE * sizeof(*block), PAGE_EXECUTE_READ, NULL ); + prev = InterlockedCompareExchangePointer( (void **)&method_blocks[num], block, NULL ); + if (prev) /* someone beat us to it */ + { + VirtualFree( block, 0, MEM_RELEASE ); + block = prev; + } + return block; +} + +static BOOL fill_stubless_table( IUnknownVtbl *vtbl, DWORD num ) +{ + const void **entry = (const void **)(vtbl + 1); + DWORD i, j; + + if (num - 3 > BLOCK_SIZE * MAX_BLOCKS) + { + FIXME( "%u methods not supported\n", num ); + return FALSE; + } + for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++) + { + const struct thunk *block = method_blocks[i]; + if (!block && !(block = allocate_block( i ))) return FALSE; + for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++, entry++) + if (*entry == (LPVOID)-1) *entry = &block[j]; + } + return TRUE; } #else /* __i386__ */ -/* can't do that on this arch */ -struct StublessThunk { int dummy; }; -#define FILL_STUBLESS(x,idx,stk) \ - ERR("stubless proxies are not supported on this architecture\n"); -#define STACK_ADJUST 0 +static BOOL fill_stubless_table( IUnknownVtbl *vtbl, DWORD num ) +{ + ERR("stubless proxies are not supported on this architecture\n"); + return FALSE; +} #endif /* __i386__ */ -HRESULT WINAPI StdProxy_Construct(REFIID riid, - LPUNKNOWN pUnkOuter, - const ProxyFileInfo *ProxyInfo, - int Index, - LPPSFACTORYBUFFER pPSFactory, - LPRPCPROXYBUFFER *ppProxy, - LPVOID *ppvObj) +HRESULT StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + const ProxyFileInfo *ProxyInfo, + int Index, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj) { StdProxyImpl *This; - const MIDL_STUBLESS_PROXY_INFO *stubless = NULL; PCInterfaceName name = ProxyInfo->pNamesArray[Index]; CInterfaceProxyVtbl *vtbl = ProxyInfo->pProxyVtblList[Index]; @@ -129,14 +176,12 @@ HRESULT WINAPI StdProxy_Construct(REFIID riid, /* TableVersion = 2 means it is the stubless version of CInterfaceProxyVtbl */ if (ProxyInfo->TableVersion > 1) { - stubless = *(const void **)vtbl; + ULONG count = ProxyInfo->pStubVtblList[Index]->header.DispatchTableCount; vtbl = (CInterfaceProxyVtbl *)((const void **)vtbl + 1); - TRACE("stubless=%p\n", stubless); + TRACE("stubless vtbl %p: count=%d\n", vtbl->Vtbl, count ); + fill_stubless_table( (IUnknownVtbl *)vtbl->Vtbl, count ); } - TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); - TRACE("vtbl=%p\n", vtbl->Vtbl); - if (!IsEqualGUID(vtbl->header.piid, riid)) { ERR("IID mismatch during proxy creation\n"); return RPC_E_UNEXPECTED; @@ -145,51 +190,37 @@ HRESULT WINAPI StdProxy_Construct(REFIID riid, This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(StdProxyImpl)); if (!This) return E_OUTOFMEMORY; - if (stubless) { - CInterfaceStubVtbl *svtbl = ProxyInfo->pStubVtblList[Index]; - unsigned long i, count = svtbl->header.DispatchTableCount; - /* Maybe the original vtbl is just modified directly to point at - * ObjectStublessClientXXX thunks in real Windows, but I don't like it - */ - TRACE("stubless thunks: count=%ld\n", count); - This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count); - This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count); - for (i=0; ithunks[i]; - if (vtbl->Vtbl[i] == (LPVOID)-1) { - PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i]; - unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; - TRACE("method %ld: stacksize=%d\n", i, bytes); - FILL_STUBLESS(thunk, i, bytes) - This->PVtbl[i] = thunk; - } - else { - memset(thunk, 0, sizeof(struct StublessThunk)); - This->PVtbl[i] = vtbl->Vtbl[i]; - } - } - } - else - This->PVtbl = vtbl->Vtbl; - + if (!pUnkOuter) pUnkOuter = (IUnknown *)This; This->lpVtbl = &StdProxy_Vtbl; + This->PVtbl = vtbl->Vtbl; /* one reference for the proxy */ This->RefCount = 1; - This->stubless = stubless; This->piid = vtbl->header.piid; + This->base_object = NULL; + This->base_proxy = NULL; This->pUnkOuter = pUnkOuter; This->name = name; This->pPSFactory = pPSFactory; This->pChannel = NULL; + + if(ProxyInfo->pDelegatedIIDs && ProxyInfo->pDelegatedIIDs[Index]) + { + HRESULT r = create_proxy( ProxyInfo->pDelegatedIIDs[Index], NULL, + &This->base_proxy, (void **)&This->base_object ); + if (FAILED(r)) + { + HeapFree( GetProcessHeap(), 0, This ); + return r; + } + } + *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; *ppvObj = &This->PVtbl; - /* if there is no outer unknown then the caller will control the lifetime - * of the proxy object through the proxy buffer, so no need to increment the - * ref count of the proxy object */ - if (pUnkOuter) - IUnknown_AddRef((IUnknown *)*ppvObj); + IUnknown_AddRef((IUnknown *)*ppvObj); IPSFactoryBuffer_AddRef(pPSFactory); + TRACE( "iid=%s this %p proxy %p obj %p vtbl %p base proxy %p base obj %p\n", + debugstr_guid(riid), This, *ppProxy, *ppvObj, This->PVtbl, This->base_proxy, This->base_object ); return S_OK; } @@ -200,11 +231,10 @@ static void StdProxy_Destruct(LPRPCPROXYBUFFER iface) if (This->pChannel) IRpcProxyBuffer_Disconnect(iface); + if (This->base_object) IUnknown_Release( This->base_object ); + if (This->base_proxy) IRpcProxyBuffer_Release( This->base_proxy ); + IPSFactoryBuffer_Release(This->pPSFactory); - if (This->thunks) { - HeapFree(GetProcessHeap(),0,This->PVtbl); - HeapFree(GetProcessHeap(),0,This->thunks); - } HeapFree(GetProcessHeap(),0,This); } @@ -259,6 +289,7 @@ static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, This->pChannel = pChannel; IRpcChannelBuffer_AddRef(pChannel); + if (This->base_proxy) IRpcProxyBuffer_Connect( This->base_proxy, pChannel ); return S_OK; } @@ -267,6 +298,8 @@ static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface) ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); TRACE("(%p)->Disconnect()\n",This); + if (This->base_proxy) IRpcProxyBuffer_Disconnect( This->base_proxy ); + IRpcChannelBuffer_Release(This->pChannel); This->pChannel = NULL; } diff --git a/reactos/dll/win32/rpcrt4/cpsf.c b/reactos/dll/win32/rpcrt4/cpsf.c index bece899d964..ac1eccf56fa 100644 --- a/reactos/dll/win32/rpcrt4/cpsf.c +++ b/reactos/dll/win32/rpcrt4/cpsf.c @@ -145,6 +145,41 @@ static const IPSFactoryBufferVtbl CStdPSFactory_Vtbl = CStdPSFactory_CreateStub }; + +static void init_psfactory( CStdPSFactoryBuffer *psfac, const ProxyFileInfo **file_list ) +{ + DWORD i, j, k; + + psfac->lpVtbl = &CStdPSFactory_Vtbl; + psfac->RefCount = 0; + psfac->pProxyFileList = file_list; + for (i = 0; file_list[i]; i++) + { + const PCInterfaceProxyVtblList *proxies = file_list[i]->pProxyVtblList; + const PCInterfaceStubVtblList *stubs = file_list[i]->pStubVtblList; + + for (j = 0; j < file_list[i]->TableSize; j++) + { + /* FIXME: i think that different vtables should be copied for + * async interfaces */ + void * const *pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Vtbl; + void **pRpcStubVtbl = (void **)&stubs[j]->Vtbl; + + if (file_list[i]->pDelegatedIIDs && file_list[i]->pDelegatedIIDs[j]) + { + void **vtbl = proxies[j]->Vtbl; + if (file_list[i]->TableVersion > 1) vtbl++; + fill_delegated_proxy_table( (IUnknownVtbl *)vtbl, stubs[j]->header.DispatchTableCount ); + pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Delegating_Vtbl; + } + + for (k = 0; k < sizeof(IRpcStubBufferVtbl)/sizeof(void *); k++) + if (!pRpcStubVtbl[k]) pRpcStubVtbl[k] = pSrcRpcStubVtbl[k]; + } + } +} + + /*********************************************************************** * NdrDllGetClassObject [RPCRT4.@] */ @@ -158,35 +193,8 @@ HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, pPSFactoryBuffer); *ppv = NULL; - if (!pPSFactoryBuffer->lpVtbl) { - const ProxyFileInfo **pProxyFileList2; - DWORD max_delegating_vtbl_size = 0; - pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; - pPSFactoryBuffer->RefCount = 0; - pPSFactoryBuffer->pProxyFileList = pProxyFileList; - for (pProxyFileList2 = pProxyFileList; *pProxyFileList2; pProxyFileList2++) { - int i; - for (i = 0; i < (*pProxyFileList2)->TableSize; i++) { - /* FIXME: i think that different vtables should be copied for - * async interfaces */ - void * const *pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Vtbl; - void **pRpcStubVtbl = (void **)&(*pProxyFileList2)->pStubVtblList[i]->Vtbl; - unsigned int j; + if (!pPSFactoryBuffer->lpVtbl) init_psfactory( pPSFactoryBuffer, pProxyFileList ); - if ((*pProxyFileList2)->pDelegatedIIDs && (*pProxyFileList2)->pDelegatedIIDs[i]) { - pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Delegating_Vtbl; - if ((*pProxyFileList2)->pStubVtblList[i]->header.DispatchTableCount > max_delegating_vtbl_size) - max_delegating_vtbl_size = (*pProxyFileList2)->pStubVtblList[i]->header.DispatchTableCount; - } - - for (j = 0; j < sizeof(IRpcStubBufferVtbl)/sizeof(void *); j++) - if (!pRpcStubVtbl[j]) - pRpcStubVtbl[j] = pSrcRpcStubVtbl[j]; - } - } - if(max_delegating_vtbl_size > 0) - create_delegating_vtbl(max_delegating_vtbl_size); - } if (pclsid && IsEqualGUID(rclsid, pclsid)) return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); else { @@ -207,7 +215,7 @@ HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, */ HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer) { - return !(pPSFactoryBuffer->RefCount); + return pPSFactoryBuffer->RefCount != 0 ? S_FALSE : S_OK; } @@ -266,7 +274,7 @@ HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, if (len && len < sizeof(module)) { TRACE("registering CLSID %s => %s\n", debugstr_w(clsid), debugstr_w(module)); if (RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key) == ERROR_SUCCESS) { - RegSetValueExW(subkey, NULL, 0, REG_SZ, (const BYTE *)psfactoryW, sizeof(psfactoryW)); + RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)psfactoryW, sizeof(psfactoryW)); if (RegCreateKeyW(key, inprocserverW, &subkey) == ERROR_SUCCESS) { RegSetValueExW(subkey, NULL, 0, REG_SZ, (LPBYTE)module, (strlenW(module)+1)*sizeof(WCHAR)); RegSetValueExW(subkey, threadingmodelW, 0, REG_SZ, (const BYTE *)bothW, sizeof(bothW)); diff --git a/reactos/dll/win32/rpcrt4/cpsf.h b/reactos/dll/win32/rpcrt4/cpsf.h index d8867d40e60..9cc046ff7ca 100644 --- a/reactos/dll/win32/rpcrt4/cpsf.h +++ b/reactos/dll/win32/rpcrt4/cpsf.h @@ -21,36 +21,25 @@ #ifndef __WINE_CPSF_H #define __WINE_CPSF_H -HRESULT WINAPI StdProxy_Construct(REFIID riid, - LPUNKNOWN pUnkOuter, - const ProxyFileInfo *ProxyInfo, - int Index, - LPPSFACTORYBUFFER pPSFactory, - LPRPCPROXYBUFFER *ppProxy, - LPVOID *ppvObj); +HRESULT StdProxy_Construct(REFIID riid, LPUNKNOWN pUnkOuter, const ProxyFileInfo *ProxyInfo, + int Index, LPPSFACTORYBUFFER pPSFactory, LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj); -HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, - LPUNKNOWN pUnkServer, - PCInterfaceName name, - CInterfaceStubVtbl *vtbl, - LPPSFACTORYBUFFER pPSFactory, - LPRPCSTUBBUFFER *ppStub); +HRESULT CStdStubBuffer_Construct(REFIID riid, LPUNKNOWN pUnkServer, PCInterfaceName name, + CInterfaceStubVtbl *vtbl, LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub); -HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, - LPUNKNOWN pUnkServer, - PCInterfaceName name, - CInterfaceStubVtbl *vtbl, - REFIID delegating_iid, - LPPSFACTORYBUFFER pPSFactory, - LPRPCSTUBBUFFER *ppStub); +HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid, LPUNKNOWN pUnkServer, PCInterfaceName name, + CInterfaceStubVtbl *vtbl, REFIID delegating_iid, + LPPSFACTORYBUFFER pPSFactory, LPRPCSTUBBUFFER *ppStub); const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface); const IRpcStubBufferVtbl CStdStubBuffer_Vtbl; const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl; -void create_delegating_vtbl(DWORD num_methods); - +BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num); +HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv); HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub); #endif /* __WINE_CPSF_H */ diff --git a/reactos/dll/win32/rpcrt4/cstub.c b/reactos/dll/win32/rpcrt4/cstub.c index 85411cd81e9..95ac1d89af2 100644 --- a/reactos/dll/win32/rpcrt4/cstub.c +++ b/reactos/dll/win32/rpcrt4/cstub.c @@ -2,6 +2,7 @@ * COM stub (CStdStubBuffer) implementation * * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2009 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -61,12 +62,12 @@ static inline cstdstubbuffer_delegating_t *impl_from_delegating( IRpcStubBuffer return (cstdstubbuffer_delegating_t*)((char *)iface - FIELD_OFFSET(cstdstubbuffer_delegating_t, stub_buffer)); } -HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, - LPUNKNOWN pUnkServer, - PCInterfaceName name, - CInterfaceStubVtbl *vtbl, - LPPSFACTORYBUFFER pPSFactory, - LPRPCSTUBBUFFER *ppStub) +HRESULT CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) { CStdStubBuffer *This; IUnknown *pvServer; @@ -113,20 +114,16 @@ typedef struct { DWORD ref; DWORD size; - void **methods; IUnknownVtbl vtbl; /* remaining entries in vtbl */ } ref_counted_vtbl; -static struct -{ - ref_counted_vtbl *table; -} current_vtbl; +static ref_counted_vtbl *current_vtbl; static HRESULT WINAPI delegating_QueryInterface(IUnknown *pUnk, REFIID iid, void **ppv) { - *ppv = (void *)pUnk; + *ppv = pUnk; return S_OK; } @@ -161,87 +158,137 @@ typedef struct { } vtbl_method_t; #include "poppack.h" -static void fill_table(IUnknownVtbl *vtbl, void **methods, DWORD num) -{ - vtbl_method_t *method; - void **entry; - DWORD i; +#define BLOCK_SIZE 1024 +#define MAX_BLOCKS 64 /* 64k methods should be enough for anybody */ +static const vtbl_method_t *method_blocks[MAX_BLOCKS]; + +static const vtbl_method_t *allocate_block( unsigned int num ) +{ + unsigned int i; + vtbl_method_t *prev, *block; + + block = VirtualAlloc( NULL, BLOCK_SIZE * sizeof(*block), + MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); + if (!block) return NULL; + + for (i = 0; i < BLOCK_SIZE; i++) + { + block[i].mov1 = 0x0424448b; + block[i].mov2 = 0x408b; + block[i].sixteen = 0x10; + block[i].mov3 = 0x04244489; + block[i].mov4 = 0x008b; + block[i].mov5 = 0x808b; + block[i].offset = (BLOCK_SIZE * num + i + 3) << 2; + block[i].jmp = 0xe0ff; + block[i].pad[0] = 0x8d; + block[i].pad[1] = 0x76; + block[i].pad[2] = 0x00; + } + VirtualProtect( block, BLOCK_SIZE * sizeof(*block), PAGE_EXECUTE_READ, NULL ); + prev = InterlockedCompareExchangePointer( (void **)&method_blocks[num], block, NULL ); + if (prev) /* someone beat us to it */ + { + VirtualFree( block, 0, MEM_RELEASE ); + block = prev; + } + return block; +} + +static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num) +{ + const void **entry = (const void **)(vtbl + 1); + DWORD i, j; + + if (num - 3 > BLOCK_SIZE * MAX_BLOCKS) + { + FIXME( "%u methods not supported\n", num ); + return FALSE; + } vtbl->QueryInterface = delegating_QueryInterface; vtbl->AddRef = delegating_AddRef; vtbl->Release = delegating_Release; - - method = (vtbl_method_t*)methods; - entry = (void**)(vtbl + 1); - - for(i = 3; i < num; i++) + for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++) { - *entry = method; - method->mov1 = 0x0424448b; - method->mov2 = 0x408b; - method->sixteen = 0x10; - method->mov3 = 0x04244489; - method->mov4 = 0x008b; - method->mov5 = 0x808b; - method->offset = i << 2; - method->jmp = 0xe0ff; - method->pad[0] = 0x8d; - method->pad[1] = 0x76; - method->pad[2] = 0x00; - - method++; - entry++; + const vtbl_method_t *block = method_blocks[i]; + if (!block && !(block = allocate_block( i ))) return FALSE; + for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++) *entry++ = &block[j]; } + return TRUE; +} + +BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) +{ + const void **entry = (const void **)(vtbl + 1); + DWORD i, j; + + if (num - 3 > BLOCK_SIZE * MAX_BLOCKS) + { + FIXME( "%u methods not supported\n", num ); + return FALSE; + } + vtbl->QueryInterface = IUnknown_QueryInterface_Proxy; + vtbl->AddRef = IUnknown_AddRef_Proxy; + vtbl->Release = IUnknown_Release_Proxy; + for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++) + { + const vtbl_method_t *block = method_blocks[i]; + if (!block && !(block = allocate_block( i ))) return FALSE; + for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++, entry++) + if (!*entry) *entry = &block[j]; + } + return TRUE; } #else /* __i386__ */ -typedef struct {int dummy;} vtbl_method_t; -static void fill_table(IUnknownVtbl *vtbl, void **methods, DWORD num) +static BOOL fill_delegated_stub_table(IUnknownVtbl *vtbl, DWORD num) { ERR("delegated stubs are not supported on this architecture\n"); + return FALSE; +} + +BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num) +{ + ERR("delegated proxies are not supported on this architecture\n"); + return FALSE; } #endif /* __i386__ */ -void create_delegating_vtbl(DWORD num_methods) -{ - TRACE("%d\n", num_methods); - if(num_methods <= 3) - { - ERR("should have more than %d methods\n", num_methods); - return; - } - - EnterCriticalSection(&delegating_vtbl_section); - 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, 0, MEM_RELEASE); - HeapFree(GetProcessHeap(), 0, current_vtbl.table); - } - 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.table->size = num_methods; - current_vtbl.table->methods = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - fill_table(¤t_vtbl.table->vtbl, current_vtbl.table->methods, num_methods); - VirtualProtect(current_vtbl.table->methods, size, PAGE_EXECUTE_READ, &old_protect); - } - LeaveCriticalSection(&delegating_vtbl_section); -} - -static IUnknownVtbl *get_delegating_vtbl(void) +static IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) { IUnknownVtbl *ret; + if (num_methods < 256) num_methods = 256; /* avoid frequent reallocations */ + EnterCriticalSection(&delegating_vtbl_section); - current_vtbl.table->ref++; - ret = ¤t_vtbl.table->vtbl; + + if(!current_vtbl || num_methods > current_vtbl->size) + { + ref_counted_vtbl *table = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(ref_counted_vtbl, vtbl) + num_methods * sizeof(void*)); + if (!table) + { + LeaveCriticalSection(&delegating_vtbl_section); + return NULL; + } + + table->ref = 0; + table->size = num_methods; + fill_delegated_stub_table(&table->vtbl, num_methods); + + if (current_vtbl && current_vtbl->ref == 0) + { + TRACE("freeing old table\n"); + HeapFree(GetProcessHeap(), 0, current_vtbl); + } + current_vtbl = table; + } + + current_vtbl->ref++; + ret = ¤t_vtbl->vtbl; LeaveCriticalSection(&delegating_vtbl_section); return ret; } @@ -253,22 +300,21 @@ static void release_delegating_vtbl(IUnknownVtbl *vtbl) EnterCriticalSection(&delegating_vtbl_section); table->ref--; TRACE("ref now %d\n", table->ref); - if(table->ref == 0 && table != current_vtbl.table) + if(table->ref == 0 && table != current_vtbl) { TRACE("... and we're not current so free'ing\n"); - VirtualFree(current_vtbl.table->methods, 0, MEM_RELEASE); HeapFree(GetProcessHeap(), 0, table); } LeaveCriticalSection(&delegating_vtbl_section); } -HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, - LPUNKNOWN pUnkServer, - PCInterfaceName name, - CInterfaceStubVtbl *vtbl, - REFIID delegating_iid, - LPPSFACTORYBUFFER pPSFactory, - LPRPCSTUBBUFFER *ppStub) +HRESULT CStdStubBuffer_Delegating_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + REFIID delegating_iid, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) { cstdstubbuffer_delegating_t *This; IUnknown *pvServer; @@ -294,7 +340,7 @@ HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, return E_OUTOFMEMORY; } - This->base_obj = get_delegating_vtbl(); + This->base_obj = get_delegating_vtbl( vtbl->header.DispatchTableCount ); r = create_stub(delegating_iid, (IUnknown*)&This->base_obj, &This->base_stub); if(FAILED(r)) { diff --git a/reactos/dll/win32/rpcrt4/epm_towers.h b/reactos/dll/win32/rpcrt4/epm_towers.h index 1afd3eb3376..3eec37aa228 100644 --- a/reactos/dll/win32/rpcrt4/epm_towers.h +++ b/reactos/dll/win32/rpcrt4/epm_towers.h @@ -19,7 +19,7 @@ * */ -#include "epm_c.h" +#include "epm.h" #define EPM_PROTOCOL_DNET_NSP 0x04 #define EPM_PROTOCOL_OSI_TP4 0x05 diff --git a/reactos/dll/win32/rpcrt4/ndr_contexthandle.c b/reactos/dll/win32/rpcrt4/ndr_contexthandle.c index 15192a72878..cab0fc5d86e 100644 --- a/reactos/dll/win32/rpcrt4/ndr_contexthandle.c +++ b/reactos/dll/win32/rpcrt4/ndr_contexthandle.c @@ -59,7 +59,7 @@ 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; + struct context_handle_entry *che = CContext; if (che->magic != NDR_CONTEXT_HANDLE_MAGIC) return NULL; @@ -111,7 +111,7 @@ void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff) } else { - ndr_context_handle *wire_data = (ndr_context_handle *)pBuff; + ndr_context_handle *wire_data = pBuff; wire_data->attributes = 0; wire_data->uuid = GUID_NULL; } diff --git a/reactos/dll/win32/rpcrt4/ndr_misc.h b/reactos/dll/win32/rpcrt4/ndr_misc.h index c3beff4d725..b0150c3a2eb 100644 --- a/reactos/dll/win32/rpcrt4/ndr_misc.h +++ b/reactos/dll/win32/rpcrt4/ndr_misc.h @@ -62,6 +62,6 @@ extern const NDR_BUFFERSIZE NdrBufferSizer[]; extern const NDR_MEMORYSIZE NdrMemorySizer[]; extern const NDR_FREE NdrFreer[]; -unsigned long ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat); +ULONG ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat); #endif /* __WINE_NDR_MISC_H */ diff --git a/reactos/dll/win32/rpcrt4/ndr_ole.c b/reactos/dll/win32/rpcrt4/ndr_ole.c index a3264e70122..a4c23c2c5c2 100644 --- a/reactos/dll/win32/rpcrt4/ndr_ole.c +++ b/reactos/dll/win32/rpcrt4/ndr_ole.c @@ -369,6 +369,30 @@ void WINAPI NdrOleFree(void *NodeToFree) COM_MemFree(NodeToFree); } +/*********************************************************************** + * Helper function to create a proxy. + * Probably similar to NdrpCreateProxy. + */ +HRESULT create_proxy(REFIID iid, IUnknown *pUnkOuter, IRpcProxyBuffer **pproxy, void **ppv) +{ + CLSID clsid; + IPSFactoryBuffer *psfac; + HRESULT r; + + if(!LoadCOM()) return E_FAIL; + + r = COM_GetPSClsid( iid, &clsid ); + if(FAILED(r)) return r; + + r = COM_GetClassObject( &clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (void**)&psfac ); + if(FAILED(r)) return r; + + r = IPSFactoryBuffer_CreateProxy(psfac, pUnkOuter, iid, pproxy, ppv); + + IPSFactoryBuffer_Release(psfac); + return r; +} + /*********************************************************************** * Helper function to create a stub. * This probably looks very much like NdrpCreateStub. diff --git a/reactos/dll/win32/rpcrt4/ndr_stubless.c b/reactos/dll/win32/rpcrt4/ndr_stubless.c index 645a0ca4729..8cb5f2b5e45 100644 --- a/reactos/dll/win32/rpcrt4/ndr_stubless.c +++ b/reactos/dll/win32/rpcrt4/ndr_stubless.c @@ -173,7 +173,7 @@ static PFORMAT_STRING client_get_handle( if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR) pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset); else - pArg = (void *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset); + pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset); memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf); pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index]; *phBinding = pGenPair->pfnBind(pObject); @@ -256,7 +256,7 @@ static void client_free_handle( if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR) pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset); else - pArg = (void *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset); + pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset); memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf); pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index]; pGenPair->pfnUnbind(pObject, hBinding); @@ -867,9 +867,14 @@ __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigne LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size); __ASM_GLOBAL_FUNC(call_server_func, "pushl %ebp\n\t" - "movl %esp, %ebp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") + "movl %esp,%ebp\n\t" + __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") "pushl %edi\n\t" /* Save registers */ + __ASM_CFI(".cfi_rel_offset %edi,-4\n\t") "pushl %esi\n\t" + __ASM_CFI(".cfi_rel_offset %esi,-8\n\t") "movl 16(%ebp), %eax\n\t" /* Get stack size */ "subl %eax, %esp\n\t" /* Make room in stack for arguments */ "andl $~15, %esp\n\t" /* Make sure stack has 16-byte alignment for Mac OS X */ @@ -882,9 +887,13 @@ __ASM_GLOBAL_FUNC(call_server_func, "call *8(%ebp)\n\t" /* Call function */ "leal -8(%ebp), %esp\n\t" /* Restore stack */ "popl %esi\n\t" /* Restore registers */ + __ASM_CFI(".cfi_same_value %esi\n\t") "popl %edi\n\t" + __ASM_CFI(".cfi_same_value %edi\n\t") "popl %ebp\n\t" - "ret\n" ) + __ASM_CFI(".cfi_def_cfa %esp,4\n\t") + __ASM_CFI(".cfi_same_value %ebp\n\t") + "ret" ) #else #warning call_server_func not implemented for your architecture LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size) @@ -1522,3 +1531,339 @@ void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg) DWORD dwPhase; NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase); } + +struct async_call_data +{ + MIDL_STUB_MESSAGE *pStubMsg; + const NDR_PROC_HEADER *pProcHeader; + PFORMAT_STRING pHandleFormat; + PFORMAT_STRING pParamFormat; + RPC_BINDING_HANDLE hBinding; + /* size of stack */ + unsigned short stack_size; + /* number of parameters. optional for client to give it to us */ + unsigned char number_of_params; + /* correlation cache */ + unsigned long NdrCorrCache[256]; +}; + +LONG_PTR WINAPIV NdrAsyncClientCall(PMIDL_STUB_DESC pStubDesc, + PFORMAT_STRING pFormat, ...) +{ + /* pointer to start of stack where arguments start */ + PRPC_MESSAGE pRpcMsg; + PMIDL_STUB_MESSAGE pStubMsg; + RPC_ASYNC_STATE *pAsync; + struct async_call_data *async_call_data; + /* procedure number */ + unsigned short procedure_number; + /* cache of Oif_flags from v2 procedure header */ + INTERPRETER_OPT_FLAGS Oif_flags = { 0 }; + /* cache of extension flags from NDR_PROC_HEADER_EXTS */ + INTERPRETER_OPT_FLAGS2 ext_flags = { 0 }; + /* the type of pass we are currently doing */ + int phase; + /* header for procedure string */ + const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0]; + /* -Oif or -Oicf generated format */ + BOOL bV2Format = FALSE; + + TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat); + + /* Later NDR language versions probably won't be backwards compatible */ + if (pStubDesc->Version > 0x50002) + { + FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version); + RpcRaiseException(RPC_X_WRONG_STUB_VERSION); + } + + async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE)); + if (!async_call_data) RpcRaiseException(ERROR_OUTOFMEMORY); + async_call_data->number_of_params = ~0; + async_call_data->pProcHeader = pProcHeader; + + async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1); + pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1); + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) + { + const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0]; + async_call_data->stack_size = pProcHeader->stack_size; + procedure_number = pProcHeader->proc_num; + pFormat += sizeof(NDR_PROC_HEADER_RPC); + } + else + { + async_call_data->stack_size = pProcHeader->stack_size; + procedure_number = pProcHeader->proc_num; + pFormat += sizeof(NDR_PROC_HEADER); + } + TRACE("stack size: 0x%x\n", async_call_data->stack_size); + TRACE("proc num: %d\n", procedure_number); + + /* create the full pointer translation tables, if requested */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT); + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + ERR("objects not supported\n"); + I_RpcFree(async_call_data); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + + NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number); + + TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags); + TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion); + + /* needed for conformance of top-level objects */ +#ifdef __i386__ + pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size); + /* FIXME: this may read one more DWORD than is necessary, but it shouldn't hurt */ + memcpy(pStubMsg->StackTop, *(unsigned char **)(&pFormat+1), async_call_data->stack_size); +#else +# warning Stack not retrieved for your CPU architecture +#endif + + pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop; + pAsync->StubInfo = async_call_data; + async_call_data->pHandleFormat = pFormat; + + pFormat = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, &async_call_data->hBinding); + if (!pFormat) return 0; + + bV2Format = (pStubDesc->Version >= 0x20000); + + if (bV2Format) + { + const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = + (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat; + + Oif_flags = pOIFHeader->Oi2Flags; + async_call_data->number_of_params = pOIFHeader->number_of_params; + + pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER); + } + + TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags); + + if (Oif_flags.HasExtensions) + { + const NDR_PROC_HEADER_EXTS *pExtensions = + (const NDR_PROC_HEADER_EXTS *)pFormat; + ext_flags = pExtensions->Flags2; + pFormat += pExtensions->Size; + } + + async_call_data->pParamFormat = pFormat; + + pStubMsg->BufferLength = 0; + + /* store the RPC flags away */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) + pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; + + /* use alternate memory allocation routines */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC) + NdrRpcSmSetClientToOsf(pStubMsg); + + if (Oif_flags.HasPipes) + { + FIXME("pipes not supported yet\n"); + RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */ + /* init pipes package */ + /* NdrPipesInitialize(...) */ + } + if (ext_flags.HasNewCorrDesc) + { + /* initialize extra correlation package */ + NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0); + } + + /* order of phases: + * 1. PROXY_CALCSIZE - calculate the buffer size + * 2. PROXY_GETBUFFER - allocate the buffer + * 3. PROXY_MARHSAL - marshal [in] params into the buffer + * 4. PROXY_SENDRECEIVE - send buffer + * Then in NdrpCompleteAsyncClientCall: + * 1. PROXY_SENDRECEIVE - receive buffer + * 2. PROXY_UNMARHSAL - unmarshal [out] params from buffer + */ + for (phase = PROXY_CALCSIZE; phase <= PROXY_SENDRECEIVE; phase++) + { + RPC_STATUS status; + TRACE("phase = %d\n", phase); + switch (phase) + { + case PROXY_GETBUFFER: + /* allocate the buffer */ + if (Oif_flags.HasPipes) + /* NdrGetPipeBuffer(...) */ + FIXME("pipes not supported yet\n"); + else + { + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding); +#else + FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n"); +#endif + else + NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding); + } + pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC; + status = I_RpcAsyncSetHandle(pRpcMsg, pAsync); + if (status != RPC_S_OK) + RpcRaiseException(status); + break; + case PROXY_SENDRECEIVE: + pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC; + /* send the [in] params only */ + if (Oif_flags.HasPipes) + /* NdrPipesSend(...) */ + FIXME("pipes not supported yet\n"); + else + { + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle); +#else + FIXME("using auto handle - call NdrNsSend when it gets implemented\n"); +#endif + else + { + pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer; + status = I_RpcSend(pStubMsg->RpcMsg); + if (status != RPC_S_OK) + RpcRaiseException(status); + } + } + + break; + case PROXY_CALCSIZE: + case PROXY_MARSHAL: + if (bV2Format) + client_do_args(pStubMsg, pFormat, phase, pStubMsg->StackTop, + async_call_data->number_of_params, NULL); + else + client_do_args_old_format(pStubMsg, pFormat, phase, + pStubMsg->StackTop, async_call_data->stack_size, NULL, + (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT), FALSE); + break; + default: + ERR("shouldn't reach here. phase %d\n", phase); + break; + } + } + + TRACE("returning 0\n"); + return 0; +} + +RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply) +{ + /* pointer to start of stack where arguments start */ + PMIDL_STUB_MESSAGE pStubMsg; + struct async_call_data *async_call_data; + /* the type of pass we are currently doing */ + int phase; + /* header for procedure string */ + const NDR_PROC_HEADER * pProcHeader; + /* -Oif or -Oicf generated format */ + BOOL bV2Format; + RPC_STATUS status = RPC_S_OK; + + if (!pAsync->StubInfo) + return RPC_S_INVALID_ASYNC_HANDLE; + + async_call_data = pAsync->StubInfo; + pStubMsg = async_call_data->pStubMsg; + pProcHeader = async_call_data->pProcHeader; + + bV2Format = (pStubMsg->StubDesc->Version >= 0x20000); + + /* order of phases: + * 1. PROXY_CALCSIZE - calculate the buffer size + * 2. PROXY_GETBUFFER - allocate the buffer + * 3. PROXY_MARHSAL - marshal [in] params into the buffer + * 4. PROXY_SENDRECEIVE - send buffer + * Then in NdrpCompleteAsyncClientCall: + * 1. PROXY_SENDRECEIVE - receive buffer + * 2. PROXY_UNMARHSAL - unmarshal [out] params from buffer + */ + for (phase = PROXY_SENDRECEIVE; phase <= PROXY_UNMARSHAL; phase++) + { + switch (phase) + { + case PROXY_SENDRECEIVE: + pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC; + /* receive the [out] params */ + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle); +#else + FIXME("using auto handle - call NdrNsReceive when it gets implemented\n"); +#endif + else + { + status = I_RpcReceive(pStubMsg->RpcMsg); + if (status != RPC_S_OK) + goto cleanup; + pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + } + + /* convert strings, floating point values and endianess into our + * preferred format */ +#if 0 + if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION) + NdrConvert(pStubMsg, pFormat); +#endif + + break; + case PROXY_UNMARSHAL: + if (bV2Format) + client_do_args(pStubMsg, async_call_data->pParamFormat, phase, pStubMsg->StackTop, + async_call_data->number_of_params, Reply); + else + client_do_args_old_format(pStubMsg, async_call_data->pParamFormat, phase, + pStubMsg->StackTop, async_call_data->stack_size, Reply, FALSE, FALSE); + break; + default: + ERR("shouldn't reach here. phase %d\n", phase); + break; + } + } + +cleanup: + if (pStubMsg->fHasNewCorrDesc) + { + /* free extra correlation package */ + NdrCorrelationFree(pStubMsg); + } + + /* free the full pointer translation tables */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables); + + /* free marshalling buffer */ + NdrFreeBuffer(pStubMsg); + client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding); + + I_RpcFree(pStubMsg->StackTop); + I_RpcFree(async_call_data); + + TRACE("-- 0x%x\n", status); + return status; +} + +RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis, + struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg, + DWORD * pdwStubPhase) +{ + FIXME("unimplemented, expect crash!\n"); + return 0; +} diff --git a/reactos/dll/win32/rpcrt4/ndr_stubless.h b/reactos/dll/win32/rpcrt4/ndr_stubless.h index 9a6fb444783..87f603b6065 100644 --- a/reactos/dll/win32/rpcrt4/ndr_stubless.h +++ b/reactos/dll/win32/rpcrt4/ndr_stubless.h @@ -85,7 +85,7 @@ typedef struct _NDR_PROC_HEADER_RPC * RPCF_Asynchronous = 0x4000 - [async] MIDL attribute * Reserved = 0x8000 */ - unsigned long rpc_flags; + unsigned int rpc_flags; unsigned short proc_num; unsigned short stack_size; @@ -240,3 +240,4 @@ void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, int phase, unsigned char *args, unsigned short stack_size, unsigned char *pRetVal, BOOL object_proc, BOOL ignore_retval); +RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply); diff --git a/reactos/dll/win32/rpcrt4/rpc_assoc.c b/reactos/dll/win32/rpcrt4/rpc_assoc.c index 32e951a929a..117301f42c0 100644 --- a/reactos/dll/win32/rpcrt4/rpc_assoc.c +++ b/reactos/dll/win32/rpcrt4/rpc_assoc.c @@ -125,7 +125,7 @@ RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, - unsigned long assoc_gid, + ULONG assoc_gid, RpcAssoc **assoc_out) { RpcAssoc *assoc; @@ -223,7 +223,7 @@ static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection * RPC_MESSAGE msg; RPC_STATUS status; unsigned char *auth_data = NULL; - unsigned long auth_length; + ULONG auth_length; TRACE("sending bind request to server\n"); @@ -394,6 +394,7 @@ RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, if (status != RPC_S_OK) return status; + NewConnection->assoc = assoc; status = RPCRT4_OpenClientConnection(NewConnection); if (status != RPC_S_OK) { @@ -416,6 +417,7 @@ RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection) { assert(!Connection->server); + Connection->async_state = NULL; EnterCriticalSection(&assoc->cs); if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id; list_add_head(&assoc->free_connection_pool, &Connection->conn_pool_entry); diff --git a/reactos/dll/win32/rpcrt4/rpc_assoc.h b/reactos/dll/win32/rpcrt4/rpc_assoc.h index 1ce1f135638..70fb664e31d 100644 --- a/reactos/dll/win32/rpcrt4/rpc_assoc.h +++ b/reactos/dll/win32/rpcrt4/rpc_assoc.h @@ -34,6 +34,7 @@ typedef struct _RpcAssoc /* id of this association group */ ULONG assoc_group_id; + UUID http_uuid; CRITICAL_SECTION cs; @@ -49,7 +50,7 @@ RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endp 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_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, ULONG 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); diff --git a/reactos/dll/win32/rpcrt4/rpc_async.c b/reactos/dll/win32/rpcrt4/rpc_async.c index 33fdc774304..891fc5ad725 100644 --- a/reactos/dll/win32/rpcrt4/rpc_async.c +++ b/reactos/dll/win32/rpcrt4/rpc_async.c @@ -29,11 +29,17 @@ #include "rpc_binding.h" #include "rpc_message.h" +#include "ndr_stubless.h" WINE_DEFAULT_DEBUG_CHANNEL(rpc); #define RPC_ASYNC_SIGNATURE 0x43595341 +static inline BOOL valid_async_handle(PRPC_ASYNC_STATE pAsync) +{ + return pAsync->Signature == RPC_ASYNC_SIGNATURE; +} + /*********************************************************************** * RpcAsyncInitializeHandle [RPCRT4.@] * @@ -104,8 +110,14 @@ RPC_STATUS WINAPI RpcAsyncGetCallStatus(PRPC_ASYNC_STATE pAsync) */ RPC_STATUS WINAPI RpcAsyncCompleteCall(PRPC_ASYNC_STATE pAsync, void *Reply) { - FIXME("(%p, %p): stub\n", pAsync, Reply); - return RPC_S_INVALID_ASYNC_HANDLE; + TRACE("(%p, %p)\n", pAsync, Reply); + + if (!valid_async_handle(pAsync)) + return RPC_S_INVALID_ASYNC_HANDLE; + + /* FIXME: check completed */ + + return NdrpCompleteAsyncClientCall(pAsync, Reply); } /*********************************************************************** diff --git a/reactos/dll/win32/rpcrt4/rpc_binding.c b/reactos/dll/win32/rpcrt4/rpc_binding.c index 696887cb7b3..29e0709e54f 100644 --- a/reactos/dll/win32/rpcrt4/rpc_binding.c +++ b/reactos/dll/win32/rpcrt4/rpc_binding.c @@ -661,11 +661,11 @@ RPC_STATUS WINAPI RpcStringBindingParseA( RPC_CSTR StringBinding, RPC_CSTR *ObjU return RPC_S_OK; fail: - if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid); - if (Protseq) RpcStringFreeA((unsigned char**)Protseq); - if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr); - if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint); - if (Options) RpcStringFreeA((unsigned char**)Options); + if (ObjUuid) RpcStringFreeA(ObjUuid); + if (Protseq) RpcStringFreeA(Protseq); + if (NetworkAddr) RpcStringFreeA(NetworkAddr); + if (Endpoint) RpcStringFreeA(Endpoint); + if (Options) RpcStringFreeA(Options); return RPC_S_INVALID_STRING_BINDING; } @@ -796,7 +796,7 @@ RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding ) RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector ) { RPC_STATUS status; - unsigned long c; + ULONG c; TRACE("(%p)\n", BindingVector); for (c=0; c<(*BindingVector)->Count; c++) { @@ -812,7 +812,7 @@ RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector ) */ RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) { - RpcBinding* bind = (RpcBinding*)Binding; + RpcBinding* bind = Binding; TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid)); *ObjectUuid = bind->ObjectUuid; @@ -824,7 +824,7 @@ RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectU */ RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) { - RpcBinding* bind = (RpcBinding*)Binding; + RpcBinding* bind = Binding; TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid)); if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; @@ -856,11 +856,11 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingA( RPC_CSTR StringBinding, RPC_BIND if (ret == RPC_S_OK) ret = RPCRT4_CompleteBindingA(bind, (char*)NetworkAddr, (char*)Endpoint, (char*)Options); - RpcStringFreeA((unsigned char**)&Options); - RpcStringFreeA((unsigned char**)&Endpoint); - RpcStringFreeA((unsigned char**)&NetworkAddr); - RpcStringFreeA((unsigned char**)&Protseq); - RpcStringFreeA((unsigned char**)&ObjectUuid); + RpcStringFreeA(&Options); + RpcStringFreeA(&Endpoint); + RpcStringFreeA(&NetworkAddr); + RpcStringFreeA(&Protseq); + RpcStringFreeA(&ObjectUuid); if (ret == RPC_S_OK) *Binding = (RPC_BINDING_HANDLE)bind; @@ -915,7 +915,7 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingW( RPC_WSTR StringBinding, RPC_BIND RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, RPC_CSTR *StringBinding ) { RPC_STATUS ret; - RpcBinding* bind = (RpcBinding*)Binding; + RpcBinding* bind = Binding; RPC_CSTR ObjectUuid; TRACE("(%p,%p)\n", Binding, StringBinding); @@ -946,7 +946,7 @@ RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, RPC_WS TRACE("(%p,%p)\n", Binding, StringBinding); ret = RpcBindingToStringBindingA(Binding, &str); *StringBinding = RPCRT4_strdupAtoW((char*)str); - RpcStringFreeA((unsigned char**)&str); + RpcStringFreeA(&str); return ret; } @@ -969,7 +969,7 @@ RPC_STATUS WINAPI I_RpcBindingInqTransportType( RPC_BINDING_HANDLE Binding, unsi */ RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn) { - RpcBinding* bind = (RpcBinding*)Binding; + RpcBinding* bind = Binding; TRACE( "(%p,%p): stub\n", Binding, BlockingFn ); @@ -986,7 +986,7 @@ RPC_STATUS RPC_ENTRY RpcBindingCopy( RPC_BINDING_HANDLE* DestinationBinding) { RpcBinding *DestBinding; - RpcBinding *SrcBinding = (RpcBinding*)SourceBinding; + RpcBinding *SrcBinding = SourceBinding; RPC_STATUS status; TRACE("(%p, %p)\n", SourceBinding, DestinationBinding); @@ -1501,7 +1501,7 @@ RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr, RPC_SECURITY_QOS *SecurityQos ) { - RpcBinding* bind = (RpcBinding*)Binding; + RpcBinding* bind = Binding; SECURITY_STATUS r; CredHandle cred; TimeStamp exp; @@ -1631,7 +1631,7 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr, RPC_SECURITY_QOS *SecurityQos ) { - RpcBinding* bind = (RpcBinding*)Binding; + RpcBinding* bind = Binding; SECURITY_STATUS r; CredHandle cred; TimeStamp exp; @@ -1640,7 +1640,7 @@ RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, PSecPkgInfoW packages; ULONG cbMaxToken; - TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), + TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w(ServerPrincName), AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); if (SecurityQos) @@ -1772,7 +1772,7 @@ RPCRTAPI RPC_STATUS RPC_ENTRY RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel, ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr ) { - TRACE("%p %s %u %u %p %u\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), + TRACE("%p %s %u %u %p %u\n", Binding, debugstr_w(ServerPrincName), AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr); return RpcBindingSetAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL); } diff --git a/reactos/dll/win32/rpcrt4/rpc_binding.h b/reactos/dll/win32/rpcrt4/rpc_binding.h index 5aa83079d51..036b59a5567 100644 --- a/reactos/dll/win32/rpcrt4/rpc_binding.h +++ b/reactos/dll/win32/rpcrt4/rpc_binding.h @@ -24,6 +24,7 @@ #include "rpcndr.h" #include "security.h" #include "wine/list.h" +#include "rpc_defs.h" typedef struct _RpcAuthInfo @@ -66,6 +67,7 @@ typedef struct _RpcConnection TimeStamp exp; ULONG attr; RpcAuthInfo *AuthInfo; + ULONG auth_context_id; ULONG encryption_auth_len; ULONG signature_auth_len; RpcQualityOfService *QOS; @@ -74,6 +76,7 @@ typedef struct _RpcConnection struct list conn_pool_entry; ULONG assoc_group_id; /* association group returned during binding */ RPC_ASYNC_STATE *async_state; + struct _RpcAssoc *assoc; /* association this connection is part of */ /* server-only */ /* The active interface bound to server. */ @@ -96,6 +99,7 @@ struct connection_ops { int (*wait_for_incoming_data)(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); + RPC_STATUS (*receive_fragment)(RpcConnection *conn, RpcPktHdr **Header, void **Payload); }; /* don't know what MS's structure looks like */ diff --git a/reactos/dll/win32/rpcrt4/rpc_defs.h b/reactos/dll/win32/rpcrt4/rpc_defs.h index cae77c4f356..e70731a3818 100644 --- a/reactos/dll/win32/rpcrt4/rpc_defs.h +++ b/reactos/dll/win32/rpcrt4/rpc_defs.h @@ -31,13 +31,13 @@ typedef struct unsigned char drep[4]; /* Data representation */ unsigned short frag_len; /* Data size in bytes including header and tail. */ unsigned short auth_len; /* Authentication length */ - unsigned long call_id; /* Call identifier. */ + unsigned int call_id; /* Call identifier. */ } RpcPktCommonHdr; typedef struct { RpcPktCommonHdr common; - unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned int alloc_hint; /* Data size in bytes excluding header and tail. */ unsigned short context_id; /* Presentation context identifier */ unsigned short opnum; } RpcPktRequestHdr; @@ -45,7 +45,7 @@ typedef struct typedef struct { RpcPktCommonHdr common; - unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned int alloc_hint; /* Data size in bytes excluding header and tail. */ unsigned short context_id; /* Presentation context identifier */ unsigned char cancel_count; unsigned char reserved; @@ -54,12 +54,12 @@ typedef struct typedef struct { RpcPktCommonHdr common; - unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned int alloc_hint; /* Data size in bytes excluding header and tail. */ unsigned short context_id; /* Presentation context identifier */ unsigned char cancel_count; /* Received cancel count */ unsigned char reserved; /* Force alignment! */ - unsigned long status; /* Runtime fault code (RPC_STATUS) */ - unsigned long reserved2; + unsigned int status; /* Runtime fault code (RPC_STATUS) */ + unsigned int reserved2; } RpcPktFaultHdr; typedef struct @@ -67,7 +67,7 @@ typedef struct RpcPktCommonHdr common; unsigned short max_tsize; /* Maximum transmission fragment size */ unsigned short max_rsize; /* Maximum receive fragment size */ - unsigned long assoc_gid; /* Associated group id */ + unsigned int assoc_gid; /* Associated group id */ unsigned char num_elements; /* Number of elements */ unsigned char padding[3]; /* Force alignment! */ unsigned short context_id; /* Presentation context identifier */ @@ -99,7 +99,7 @@ typedef struct RpcPktCommonHdr common; unsigned short max_tsize; /* Maximum transmission fragment size */ unsigned short max_rsize; /* Maximum receive fragment size */ - unsigned long assoc_gid; /* Associated group id */ + unsigned int assoc_gid; /* Associated group id */ /* * Following this header are these fields: * RpcAddressString server_address; @@ -120,6 +120,14 @@ typedef struct } protocols[1]; } RpcPktBindNAckHdr; +/* undocumented packet sent during RPC over HTTP */ +typedef struct +{ + RpcPktCommonHdr common; + unsigned short flags; + unsigned short num_data_items; +} RpcPktHttpHdr; + /* Union representing all possible packet headers */ typedef union { @@ -130,6 +138,7 @@ typedef union RpcPktBindHdr bind; RpcPktBindAckHdr bind_ack; RpcPktBindNAckHdr bind_nack; + RpcPktHttpHdr http; } RpcPktHdr; typedef struct @@ -138,7 +147,7 @@ typedef struct unsigned char auth_level; /* RPC_C_AUTHN_LEVEL* */ unsigned char auth_pad_length; /* length of padding to restore n % 4 alignment */ unsigned char auth_reserved; /* reserved, must be zero */ - unsigned long auth_context_id; /* unique value for the authenticated connection */ + unsigned int auth_context_id; /* unique value for the authenticated connection */ } RpcAuthVerifier; #define RPC_AUTH_VERIFIER_LEN(common_hdr) \ @@ -174,6 +183,7 @@ typedef struct #define PKT_SHUTDOWN 17 #define PKT_CO_CANCEL 18 #define PKT_ORPHANED 19 +#define PKT_HTTP 20 #define RESULT_ACCEPT 0 #define RESULT_USER_REJECTION 1 diff --git a/reactos/dll/win32/rpcrt4/rpc_epmap.c b/reactos/dll/win32/rpcrt4/rpc_epmap.c index 286ffbf9973..60c425550ad 100644 --- a/reactos/dll/win32/rpcrt4/rpc_epmap.c +++ b/reactos/dll/win32/rpcrt4/rpc_epmap.c @@ -32,7 +32,7 @@ #include "wine/exception.h" #include "rpc_binding.h" -#include "epm_c.h" +#include "epm.h" #include "epm_towers.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -116,7 +116,7 @@ static BOOL start_rpcss(void) static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle) { - RpcBinding *bind = (RpcBinding *)handle; + RpcBinding *bind = handle; const char *protseq = bind->Protseq; const char *network_addr = bind->NetworkAddr; @@ -127,7 +127,7 @@ static inline BOOL is_epm_destination_local(RPC_BINDING_HANDLE handle) static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle) { - RpcBinding *bind = (RpcBinding *)handle; + RpcBinding *bind = handle; const char * pszEndpoint = NULL; RPC_STATUS status; RpcBinding* epm_bind; @@ -149,7 +149,7 @@ static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_H status = RpcBindingCopy(handle, epm_handle); if (status != RPC_S_OK) return status; - epm_bind = (RpcBinding*)*epm_handle; + epm_bind = *epm_handle; if (epm_bind->AuthInfo) { /* don't bother with authenticating against the EPM by default @@ -187,8 +187,8 @@ static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr) RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) { - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; - unsigned long i; + PRPC_SERVER_INTERFACE If = IfSpec; + ULONG i; RPC_STATUS status = RPC_S_OK; error_status_t status2; ept_entry_t *entries; @@ -197,13 +197,13 @@ RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bind TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a((char*)Annotation)); TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); for (i=0; iCount; i++) { - RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]); - TRACE(" protseq[%ld]=%s\n", i, debugstr_a(bind->Protseq)); - TRACE(" endpoint[%ld]=%s\n", i, debugstr_a(bind->Endpoint)); + RpcBinding* bind = BindingVector->BindingH[i]; + TRACE(" protseq[%d]=%s\n", i, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%d]=%s\n", i, debugstr_a(bind->Endpoint)); } if (UuidVector) { for (i=0; iCount; i++) - TRACE(" obj[%ld]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); + TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); } if (!BindingVector->Count) return RPC_S_OK; @@ -222,10 +222,9 @@ RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bind for (i = 0; i < BindingVector->Count; i++) { unsigned j; - RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]); + RpcBinding* bind = BindingVector->BindingH[i]; for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) { - int len = strlen((char *)Annotation); status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq, bind->Endpoint, bind->NetworkAddr, @@ -236,7 +235,9 @@ RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bind memcpy(&entries[i * UuidVector->Count].object, &UuidVector->Uuid[j], sizeof(GUID)); else memset(&entries[i].object, 0, sizeof(entries[i].object)); - memcpy(entries[i].annotation, Annotation, min(len + 1, ept_max_annotation_size)); + if (Annotation) + memcpy(entries[i].annotation, Annotation, + min(strlen((char *)Annotation) + 1, ept_max_annotation_size)); } } @@ -280,14 +281,29 @@ RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bind return status; } +/*********************************************************************** + * RpcEpRegisterW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpRegisterW( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector, RPC_WSTR Annotation ) +{ + LPSTR annA = RPCRT4_strdupWtoA(Annotation); + RPC_STATUS status; + + status = RpcEpRegisterA(IfSpec, BindingVector, UuidVector, (RPC_CSTR)annA); + + HeapFree(GetProcessHeap(), 0, annA); + return status; +} + /*********************************************************************** * RpcEpUnregister (RPCRT4.@) */ RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, UUID_VECTOR *UuidVector ) { - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; - unsigned long i; + PRPC_SERVER_INTERFACE If = IfSpec; + ULONG i; RPC_STATUS status = RPC_S_OK; error_status_t status2; ept_entry_t *entries; @@ -296,13 +312,13 @@ RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bin TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector); TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); for (i=0; iCount; i++) { - RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]); - TRACE(" protseq[%ld]=%s\n", i, debugstr_a(bind->Protseq)); - TRACE(" endpoint[%ld]=%s\n", i, debugstr_a(bind->Endpoint)); + RpcBinding* bind = BindingVector->BindingH[i]; + TRACE(" protseq[%d]=%s\n", i, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%d]=%s\n", i, debugstr_a(bind->Endpoint)); } if (UuidVector) { for (i=0; iCount; i++) - TRACE(" obj[%ld]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); + TRACE(" obj[%d]=%s\n", i, debugstr_guid(UuidVector->Uuid[i])); } entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1)); @@ -319,7 +335,7 @@ RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bin for (i = 0; i < BindingVector->Count; i++) { unsigned j; - RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]); + RpcBinding* bind = BindingVector->BindingH[i]; for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++) { status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, @@ -372,8 +388,8 @@ RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bin */ RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) { - PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec; - RpcBinding* bind = (RpcBinding*)Binding; + PRPC_CLIENT_INTERFACE If = IfSpec; + RpcBinding* bind = Binding; RPC_STATUS status; error_status_t status2; handle_t handle; diff --git a/reactos/dll/win32/rpcrt4/rpc_message.c b/reactos/dll/win32/rpcrt4/rpc_message.c index e4f96a9179e..5e7c857acdd 100644 --- a/reactos/dll/win32/rpcrt4/rpc_message.c +++ b/reactos/dll/win32/rpcrt4/rpc_message.c @@ -59,13 +59,13 @@ enum secure_packet_direction static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg); -static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) +DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) { static const DWORD header_sizes[] = { sizeof(Header->request), 0, sizeof(Header->response), sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind), sizeof(Header->bind_ack), sizeof(Header->bind_nack), - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, sizeof(Header->http) }; ULONG ret = 0; @@ -76,7 +76,7 @@ static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) if (Header->common.flags & RPC_FLG_OBJECT_UUID) ret += sizeof(UUID); } else { - TRACE("invalid packet type\n"); + WARN("invalid packet type %u\n", Header->common.ptype); } return ret; @@ -96,7 +96,7 @@ static int packet_has_auth_verifier(const RpcPktHdr *Header) } static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, - unsigned long DataRepresentation) + ULONG DataRepresentation) { Header->common.rpc_ver = RPC_VER_MAJOR; Header->common.rpc_ver_minor = RPC_VER_MINOR; @@ -111,8 +111,8 @@ static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType /* Flags and fragment length are computed in RPCRT4_Send. */ } -static RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, - unsigned long BufferLength, +static RpcPktHdr *RPCRT4_BuildRequestHeader(ULONG DataRepresentation, + ULONG BufferLength, unsigned short ProcNum, UUID *ObjectUuid) { @@ -141,8 +141,7 @@ static RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, return header; } -RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, - unsigned long BufferLength) +RpcPktHdr *RPCRT4_BuildResponseHeader(ULONG DataRepresentation, ULONG BufferLength) { RpcPktHdr *header; @@ -158,8 +157,7 @@ RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, return header; } -RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, - RPC_STATUS Status) +RpcPktHdr *RPCRT4_BuildFaultHeader(ULONG DataRepresentation, RPC_STATUS Status) { RpcPktHdr *header; @@ -175,10 +173,10 @@ RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, return header; } -RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, +RpcPktHdr *RPCRT4_BuildBindHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, - unsigned long AssocGroupId, + ULONG AssocGroupId, const RPC_SYNTAX_IDENTIFIER *AbstractId, const RPC_SYNTAX_IDENTIFIER *TransferId) { @@ -202,7 +200,7 @@ RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, return header; } -static RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation) +static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation) { RpcPktHdr *header; @@ -218,7 +216,7 @@ static RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation) return header; } -RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, +RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor) { @@ -239,17 +237,17 @@ RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, return header; } -RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, +RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, - unsigned long AssocGroupId, + ULONG AssocGroupId, LPCSTR ServerAddress, - unsigned long Result, - unsigned long Reason, + unsigned short Result, + unsigned short Reason, const RPC_SYNTAX_IDENTIFIER *TransferId) { RpcPktHdr *header; - unsigned long header_size; + ULONG header_size; RpcAddressString *server_address; RpcResults *results; RPC_SYNTAX_IDENTIFIER *transfer_id; @@ -283,6 +281,118 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, return header; } +RpcPktHdr *RPCRT4_BuildHttpHeader(ULONG DataRepresentation, + unsigned short flags, + unsigned short num_data_items, + unsigned int payload_size) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->http) + payload_size); + if (header == NULL) { + ERR("failed to allocate memory\n"); + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_HTTP, DataRepresentation); + /* since the packet isn't current sent using RPCRT4_Send, set the flags + * manually here */ + header->common.flags = RPC_FLG_FIRST|RPC_FLG_LAST; + header->common.call_id = 0; + header->common.frag_len = sizeof(header->http) + payload_size; + header->http.flags = flags; + header->http.num_data_items = num_data_items; + + return header; +} + +#define WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, type, value) \ + do { \ + *(unsigned int *)(payload) = (type); \ + (payload) += 4; \ + *(unsigned int *)(payload) = (value); \ + (payload) += 4; \ + } while (0) + +#define WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, type, uuid) \ + do { \ + *(unsigned int *)(payload) = (type); \ + (payload) += 4; \ + *(UUID *)(payload) = (uuid); \ + (payload) += sizeof(UUID); \ + } while (0) + +#define WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, flow_control_increment, uuid) \ + do { \ + *(unsigned int *)(payload) = 0x00000001; \ + (payload) += 4; \ + *(unsigned int *)(payload) = (bytes_transmitted); \ + (payload) += 4; \ + *(unsigned int *)(payload) = (flow_control_increment); \ + (payload) += 4; \ + *(UUID *)(payload) = (uuid); \ + (payload) += sizeof(UUID); \ + } while (0) + +RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe, + const UUID *connection_uuid, + const UUID *pipe_uuid, + const UUID *association_uuid) +{ + RpcPktHdr *header; + unsigned int size; + char *payload; + + size = 8 + 4 + sizeof(UUID) + 4 + sizeof(UUID) + 8; + if (!out_pipe) + size += 8 + 4 + sizeof(UUID); + + header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, flags, + out_pipe ? 4 : 6, size); + if (!header) return NULL; + payload = (char *)(&header->http+1); + + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000006, 0x00000001); + + WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *connection_uuid); + WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *pipe_uuid); + + if (out_pipe) + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000000, 0x00010000); + else + { + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000004, 0x40000000); + /* FIXME: what does this part of the payload do? */ + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000005, 0x000493e0); + + WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x0000000c, *association_uuid); + } + + return header; +} + +RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, + ULONG flow_control_increment, + const UUID *pipe_uuid) +{ + RpcPktHdr *header; + char *payload; + + header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x2, 2, + 5 * sizeof(ULONG) + sizeof(UUID)); + if (!header) return NULL; + payload = (char *)(&header->http+1); + + WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x0000000d, (server ? 0x0 : 0x3)); + + WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, + flow_control_increment, *pipe_uuid); + return header; +} + VOID RPCRT4_FreeHeader(RpcPktHdr *Header) { HeapFree(GetProcessHeap(), 0, Header); @@ -362,6 +472,206 @@ static RPC_STATUS NCA2RPC_STATUS(NCA_STATUS status) } } +/* assumes the common header fields have already been validated */ +BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data, + unsigned short data_len) +{ + unsigned short i; + BYTE *p = data; + + for (i = 0; i < hdr->http.num_data_items; i++) + { + ULONG type; + + if (data_len < sizeof(ULONG)) + return FALSE; + + type = *(ULONG *)p; + p += sizeof(ULONG); + data_len -= sizeof(ULONG); + + switch (type) + { + case 0x3: + case 0xc: + if (data_len < sizeof(GUID)) + return FALSE; + p += sizeof(GUID); + data_len -= sizeof(GUID); + break; + case 0x0: + case 0x2: + case 0x4: + case 0x5: + case 0x6: + case 0xd: + if (data_len < sizeof(ULONG)) + return FALSE; + p += sizeof(ULONG); + data_len -= sizeof(ULONG); + break; + case 0x1: + if (data_len < 24) + return FALSE; + p += 24; + data_len -= 24; + break; + default: + FIXME("unimplemented type 0x%x\n", type); + break; + } + } + return TRUE; +} + +/* assumes the HTTP packet has been validated */ +static unsigned char *RPCRT4_NextHttpHeaderField(unsigned char *data) +{ + ULONG type; + + type = *(ULONG *)data; + data += sizeof(ULONG); + + switch (type) + { + case 0x3: + case 0xc: + return data + sizeof(GUID); + case 0x0: + case 0x2: + case 0x4: + case 0x5: + case 0x6: + case 0xd: + return data + sizeof(ULONG); + case 0x1: + return data + 24; + default: + FIXME("unimplemented type 0x%x\n", type); + return data; + } +} + +#define READ_HTTP_PAYLOAD_FIELD_TYPE(data) *(ULONG *)(data) +#define GET_HTTP_PAYLOAD_FIELD_DATA(data) ((data) + sizeof(ULONG)) + +/* assumes the HTTP packet has been validated */ +RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header, + unsigned char *data, ULONG *field1) +{ + ULONG type; + if (header->http.flags != 0x0) + { + ERR("invalid flags 0x%x\n", header->http.flags); + return RPC_S_PROTOCOL_ERROR; + } + if (header->http.num_data_items != 1) + { + ERR("invalid number of data items %d\n", header->http.num_data_items); + return RPC_S_PROTOCOL_ERROR; + } + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000002) + { + ERR("invalid type 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + return RPC_S_OK; +} + +/* assumes the HTTP packet has been validated */ +RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header, + unsigned char *data, ULONG *field1, + ULONG *bytes_until_next_packet, + ULONG *field3) +{ + ULONG type; + if (header->http.flags != 0x0) + { + ERR("invalid flags 0x%x\n", header->http.flags); + return RPC_S_PROTOCOL_ERROR; + } + if (header->http.num_data_items != 3) + { + ERR("invalid number of data items %d\n", header->http.num_data_items); + return RPC_S_PROTOCOL_ERROR; + } + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000006) + { + ERR("invalid type for field 1: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + data = RPCRT4_NextHttpHeaderField(data); + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000000) + { + ERR("invalid type for field 2: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *bytes_until_next_packet = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + data = RPCRT4_NextHttpHeaderField(data); + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000002) + { + ERR("invalid type for field 3: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *field3 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header, + unsigned char *data, BOOL server, + ULONG *bytes_transmitted, + ULONG *flow_control_increment, + UUID *pipe_uuid) +{ + ULONG type; + if (header->http.flags != 0x2) + { + ERR("invalid flags 0x%x\n", header->http.flags); + return RPC_S_PROTOCOL_ERROR; + } + if (header->http.num_data_items != 2) + { + ERR("invalid number of data items %d\n", header->http.num_data_items); + return RPC_S_PROTOCOL_ERROR; + } + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x0000000d) + { + ERR("invalid type for field 1: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + if (*(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data) != (server ? 0x3 : 0x0)) + { + ERR("invalid type for 0xd field data: 0x%08x\n", *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data)); + return RPC_S_PROTOCOL_ERROR; + } + data = RPCRT4_NextHttpHeaderField(data); + + type = READ_HTTP_PAYLOAD_FIELD_TYPE(data); + if (type != 0x00000001) + { + ERR("invalid type for field 2: 0x%08x\n", type); + return RPC_S_PROTOCOL_ERROR; + } + *bytes_transmitted = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data); + *flow_control_increment = *(ULONG *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 4); + *pipe_uuid = *(UUID *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 8); + + return RPC_S_OK; +} + + static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, enum secure_packet_direction dir, RpcPktHdr *hdr, unsigned int hdr_size, @@ -509,7 +819,7 @@ static RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Head auth_hdr->auth_pad_length = auth_pad_len; auth_hdr->auth_reserved = 0; /* a unique number... */ - auth_hdr->auth_context_id = (unsigned long)Connection; + auth_hdr->auth_context_id = Connection->auth_context_id; if (AuthLength) memcpy(auth_hdr + 1, Auth, AuthLength); @@ -687,7 +997,7 @@ RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, } /* validates version and frag_len fields */ -static RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr) +RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr) { DWORD hdr_length; @@ -716,11 +1026,11 @@ static RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr) } /*********************************************************************** - * RPCRT4_receive_fragment (internal) + * RPCRT4_default_receive_fragment (internal) * * Receive a fragment from a connection. */ -static RPC_STATUS RPCRT4_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload) +static RPC_STATUS RPCRT4_default_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload) { RPC_STATUS status; DWORD hdr_length; @@ -794,6 +1104,14 @@ fail: return status; } +static RPC_STATUS RPCRT4_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload) +{ + if (Connection->ops->receive_fragment) + return Connection->ops->receive_fragment(Connection, Header, Payload); + else + return RPCRT4_default_receive_fragment(Connection, Header, Payload); +} + /*********************************************************************** * RPCRT4_ReceiveWithAuth (internal) * @@ -803,14 +1121,14 @@ fail: RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg, unsigned char **auth_data_out, - unsigned long *auth_length_out) + ULONG *auth_length_out) { RPC_STATUS status; DWORD hdr_length; unsigned short first_flag; - unsigned long data_length; - unsigned long buffer_length; - unsigned long auth_length = 0; + ULONG data_length; + ULONG buffer_length; + ULONG auth_length = 0; unsigned char *auth_data = NULL; RpcPktHdr *CurrentHeader = NULL; void *payload = NULL; @@ -874,7 +1192,7 @@ RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, } if (CurrentHeader->common.auth_len != auth_length) { - WARN("auth_len header field changed from %ld to %d\n", + WARN("auth_len header field changed from %d to %d\n", auth_length, CurrentHeader->common.auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; @@ -888,7 +1206,7 @@ RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, data_length = CurrentHeader->common.frag_len - hdr_length - header_auth_len; if (data_length + buffer_length > pMsg->BufferLength) { - TRACE("allocation hint exceeded, new buffer length = %ld\n", + TRACE("allocation hint exceeded, new buffer length = %d\n", data_length + buffer_length); pMsg->BufferLength = data_length + buffer_length; status = I_RpcReAllocateBuffer(pMsg); @@ -998,7 +1316,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, */ RPC_STATUS WINAPI I_RpcNegotiateTransferSyntax(PRPC_MESSAGE pMsg) { - RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcBinding* bind = pMsg->Handle; RpcConnection* conn; RPC_STATUS status = RPC_S_OK; @@ -1063,7 +1381,7 @@ RPC_STATUS WINAPI I_RpcNegotiateTransferSyntax(PRPC_MESSAGE pMsg) RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) { RPC_STATUS status; - RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcBinding* bind = pMsg->Handle; TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); @@ -1120,7 +1438,7 @@ static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg) */ RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) { - RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcBinding* bind = pMsg->Handle; TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer); @@ -1214,7 +1532,7 @@ static DWORD WINAPI async_notifier_proc(LPVOID p) */ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) { - RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcBinding* bind = pMsg->Handle; RpcConnection* conn; RPC_STATUS status; RpcPktHdr *hdr; @@ -1268,7 +1586,7 @@ static inline BOOL is_hard_error(RPC_STATUS status) */ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) { - RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcBinding* bind = pMsg->Handle; RPC_STATUS status; RpcPktHdr *hdr = NULL; RpcConnection *conn; @@ -1287,7 +1605,7 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) case PKT_RESPONSE: break; case PKT_FAULT: - ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status); + ERR ("we got fault packet with status 0x%x\n", hdr->fault.status); status = NCA2RPC_STATUS(hdr->fault.status); if (is_hard_error(status)) goto fail; @@ -1360,7 +1678,7 @@ RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg) */ RPC_STATUS WINAPI I_RpcAsyncSetHandle(PRPC_MESSAGE pMsg, PRPC_ASYNC_STATE pAsync) { - RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcBinding* bind = pMsg->Handle; RpcConnection *conn; TRACE("(%p, %p)\n", pMsg, pAsync); diff --git a/reactos/dll/win32/rpcrt4/rpc_message.h b/reactos/dll/win32/rpcrt4/rpc_message.h index e4033882feb..aeeef0773e5 100644 --- a/reactos/dll/win32/rpcrt4/rpc_message.h +++ b/reactos/dll/win32/rpcrt4/rpc_message.h @@ -25,15 +25,25 @@ typedef unsigned int NCA_STATUS; -RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_STATUS 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, unsigned long AssocGroupId, LPCSTR ServerAddress, unsigned long Result, unsigned long Reason, const RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildFaultHeader(ULONG DataRepresentation, RPC_STATUS Status); +RpcPktHdr *RPCRT4_BuildResponseHeader(ULONG DataRepresentation, ULONG BufferLength); +RpcPktHdr *RPCRT4_BuildBindHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, ULONG AssocGroupId, const RPC_SYNTAX_IDENTIFIER *AbstractId, const RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor); +RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, ULONG AssocGroupId, LPCSTR ServerAddress, unsigned short Result, unsigned short Reason, const RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildHttpHeader(ULONG DataRepresentation, unsigned short flags, unsigned short num_data_items, unsigned int payload_size); +RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe, const UUID *connection_uuid, const UUID *pipe_uuid, const UUID *association_uuid); +RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted, ULONG flow_control_increment, const UUID *pipe_uuid); 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); -RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg, unsigned char **auth_data_out, unsigned long *auth_length_out); +RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg, unsigned char **auth_data_out, ULONG *auth_length_out); +DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header); +RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr); + +BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data, unsigned short data_len); +RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header, unsigned char *data, ULONG *field1); +RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header, unsigned char *data, ULONG *field1, ULONG *bytes_until_next_packet, ULONG *field3); +RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header, unsigned char *data, BOOL server, ULONG *bytes_transmitted, ULONG *flow_control_increment, UUID *pipe_uuid); NCA_STATUS RPC2NCA_STATUS(RPC_STATUS status); RPC_STATUS RPCRT4_AuthorizeConnection(RpcConnection* conn, BYTE *challenge, ULONG count); diff --git a/reactos/dll/win32/rpcrt4/rpc_server.c b/reactos/dll/win32/rpcrt4/rpc_server.c index 473c7ba9328..34006396220 100644 --- a/reactos/dll/win32/rpcrt4/rpc_server.c +++ b/reactos/dll/win32/rpcrt4/rpc_server.c @@ -367,7 +367,7 @@ static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) { - RpcConnection* conn = (RpcConnection*)the_arg; + RpcConnection* conn = the_arg; RpcPktHdr *hdr; RPC_MESSAGE *msg; RPC_STATUS status; @@ -449,27 +449,23 @@ static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) /* start waiting */ res = cps->ops->wait_for_new_connection(cps, count, objs); - if (res == -1) - break; - else if (res == 0) + + if (res == -1 || (res == 0 && !std_listen)) { - if (!std_listen) - { + /* cleanup */ + cps->ops->free_wait_array(cps, objs); + EnterCriticalSection(&cps->cs); + for (conn = cps->conn; conn; conn = conn->Next) + RPCRT4_CloseConnection(conn); + LeaveCriticalSection(&cps->cs); + + if (res == 0 && !std_listen) SetEvent(cps->server_ready_event); - break; - } - set_ready_event = TRUE; + break; } + else if (res == 0) + set_ready_event = TRUE; } - cps->ops->free_wait_array(cps, objs); - EnterCriticalSection(&cps->cs); - /* close connections */ - conn = cps->conn; - while (conn) { - RPCRT4_CloseConnection(conn); - conn = conn->Next; - } - LeaveCriticalSection(&cps->cs); return 0; } @@ -570,11 +566,32 @@ static void RPCRT4_stop_listen(BOOL auto_listen) LeaveCriticalSection(&listen_cs); } -static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, LPSTR endpoint) +static BOOL RPCRT4_protseq_is_endpoint_registered(RpcServerProtseq *protseq, const char *endpoint) +{ + RpcConnection *conn; + EnterCriticalSection(&protseq->cs); + for (conn = protseq->conn; conn; conn = conn->Next) + { + if (!endpoint || !strcmp(endpoint, conn->Endpoint)) + break; + } + LeaveCriticalSection(&protseq->cs); + return (conn != NULL); +} + +static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, const char *endpoint) { RPC_STATUS status; - status = ps->ops->open_endpoint(ps, endpoint); + EnterCriticalSection(&ps->cs); + + if (RPCRT4_protseq_is_endpoint_registered(ps, endpoint)) + status = RPC_S_OK; + else + status = ps->ops->open_endpoint(ps, endpoint); + + LeaveCriticalSection(&ps->cs); + if (status != RPC_S_OK) return status; @@ -608,11 +625,8 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) count = 0; LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) { EnterCriticalSection(&ps->cs); - conn = ps->conn; - while (conn) { + for (conn = ps->conn; conn; conn = conn->Next) count++; - conn = conn->Next; - } LeaveCriticalSection(&ps->cs); } if (count) { @@ -624,12 +638,10 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) count = 0; LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) { EnterCriticalSection(&ps->cs); - conn = ps->conn; - while (conn) { + for (conn = ps->conn; conn; conn = conn->Next) { RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count], conn); count++; - conn = conn->Next; } LeaveCriticalSection(&ps->cs); } @@ -681,7 +693,7 @@ RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_W * * Must be called with server_cs held. */ -static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, char *Protseq, RpcServerProtseq **ps) +static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps) { const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq); @@ -695,7 +707,7 @@ static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, char *Protseq, RpcServerPr if (!*ps) return RPC_S_OUT_OF_RESOURCES; (*ps)->MaxCalls = MaxCalls; - (*ps)->Protseq = Protseq; + (*ps)->Protseq = RPCRT4_strdupA(Protseq); (*ps)->ops = ops; (*ps)->MaxCalls = 0; (*ps)->conn = NULL; @@ -711,8 +723,19 @@ static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, char *Protseq, RpcServerPr return RPC_S_OK; } +/* must be called with server_cs held */ +static void destroy_serverprotoseq(RpcServerProtseq *ps) +{ + RPCRT4_strfree(ps->Protseq); + DeleteCriticalSection(&ps->cs); + CloseHandle(ps->mgr_mutex); + CloseHandle(ps->server_ready_event); + list_remove(&ps->entry); + HeapFree(GetProcessHeap(), 0, ps); +} + /* Finds a given protseq or creates a new one if one doesn't already exist */ -static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, char *Protseq, RpcServerProtseq **ps) +static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps) { RPC_STATUS status; RpcServerProtseq *cps; @@ -741,19 +764,18 @@ static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, char *Protse RPC_STATUS WINAPI RpcServerUseProtseqEpExA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor, PRPC_POLICY lpPolicy ) { - char *szps = (char*)Protseq, *szep = (char*)Endpoint; RpcServerProtseq* ps; RPC_STATUS status; - TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_a(szps), MaxCalls, - debugstr_a(szep), SecurityDescriptor, + TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_a((const char *)Protseq), + MaxCalls, debugstr_a((const char *)Endpoint), SecurityDescriptor, lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); - status = RPCRT4_get_or_create_serverprotseq(MaxCalls, RPCRT4_strdupA(szps), &ps); + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps); if (status != RPC_S_OK) return status; - return RPCRT4_use_protseq(ps, szep); + return RPCRT4_use_protseq(ps, (const char *)Endpoint); } /*********************************************************************** @@ -764,13 +786,16 @@ RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC { RpcServerProtseq* ps; RPC_STATUS status; + LPSTR ProtseqA; LPSTR EndpointA; TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor, lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); - status = RPCRT4_get_or_create_serverprotseq(MaxCalls, RPCRT4_strdupWtoA(Protseq), &ps); + ProtseqA = RPCRT4_strdupWtoA(Protseq); + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps); + RPCRT4_strfree(ProtseqA); if (status != RPC_S_OK) return status; @@ -785,8 +810,16 @@ RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC */ RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) { + RPC_STATUS status; + RpcServerProtseq* ps; + TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor); - return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor); + + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps); + if (status != RPC_S_OK) + return status; + + return RPCRT4_use_protseq(ps, NULL); } /*********************************************************************** @@ -794,8 +827,36 @@ RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, */ RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) { + RPC_STATUS status; + RpcServerProtseq* ps; + LPSTR ProtseqA; + TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor); - return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor); + + ProtseqA = RPCRT4_strdupWtoA(Protseq); + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps); + RPCRT4_strfree(ProtseqA); + if (status != RPC_S_OK) + return status; + + return RPCRT4_use_protseq(ps, NULL); +} + +void RPCRT4_destroy_all_protseqs(void) +{ + RpcServerProtseq *cps, *cursor2; + + if (listen_count != 0) + std_listen = FALSE; + + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY_SAFE(cps, cursor2, &protseqs, RpcServerProtseq, entry) + { + if (listen_count != 0) + RPCRT4_sync_with_server_thread(cps); + destroy_serverprotoseq(cps); + } + LeaveCriticalSection(&server_cs); } /*********************************************************************** @@ -823,7 +884,7 @@ RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn ) { - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + PRPC_SERVER_INTERFACE If = IfSpec; RpcServerInterface* sif; unsigned int i; @@ -876,7 +937,7 @@ RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, */ RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete ) { - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + PRPC_SERVER_INTERFACE If = IfSpec; HANDLE event = NULL; BOOL found = FALSE; BOOL completed = TRUE; diff --git a/reactos/dll/win32/rpcrt4/rpc_server.h b/reactos/dll/win32/rpcrt4/rpc_server.h index ffd5b016e4b..cacce794e34 100644 --- a/reactos/dll/win32/rpcrt4/rpc_server.h +++ b/reactos/dll/win32/rpcrt4/rpc_server.h @@ -56,7 +56,7 @@ struct protseq_ops * new connection was established */ int (*wait_for_new_connection)(RpcServerProtseq *protseq, unsigned int count, void *wait_array); /* opens the endpoint and optionally begins listening */ - RPC_STATUS (*open_endpoint)(RpcServerProtseq *protseq, LPSTR endpoint); + RPC_STATUS (*open_endpoint)(RpcServerProtseq *protseq, const char *endpoint); }; typedef struct _RpcServerInterface @@ -79,4 +79,6 @@ typedef struct _RpcServerInterface void RPCRT4_new_client(RpcConnection* conn); const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq); +void RPCRT4_destroy_all_protseqs(void); + #endif /* __WINE_RPC_SERVER_H */ diff --git a/reactos/dll/win32/rpcrt4/rpc_transport.c b/reactos/dll/win32/rpcrt4/rpc_transport.c index 735a19df648..dddc5135c9d 100644 --- a/reactos/dll/win32/rpcrt4/rpc_transport.c +++ b/reactos/dll/win32/rpcrt4/rpc_transport.c @@ -40,6 +40,8 @@ # ifndef EAGAIN # define EAGAIN WSAEWOULDBLOCK # endif +# undef errno +# define errno WSAGetLastError() #else # include # ifdef HAVE_UNISTD_H @@ -64,16 +66,21 @@ # ifdef HAVE_SYS_POLL_H # include # endif +# ifdef HAVE_SYS_FILIO_H +# include +# endif +# ifdef HAVE_SYS_IOCTL_H +# include +# endif # define closesocket close +# define ioctlsocket ioctl #endif /* defined(__MINGW32__) || defined (_MSC_VER) */ -#include -#include - #include "windef.h" #include "winbase.h" #include "winnls.h" #include "winerror.h" +#include "wininet.h" #include "winternl.h" #include "wine/unicode.h" @@ -83,16 +90,17 @@ #include "wine/debug.h" #include "rpc_binding.h" +#include "rpc_assoc.h" #include "rpc_message.h" #include "rpc_server.h" #include "epm_towers.h" -#include "unix_func.h" - #ifndef SOL_TCP # define SOL_TCP IPPROTO_TCP #endif +#define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000) + WINE_DEFAULT_DEBUG_CHANNEL(rpc); static RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection); @@ -258,12 +266,23 @@ static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection) return r; } -static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint) +static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint) { static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; RPC_STATUS r; LPSTR pname; RpcConnection *Connection; + char generated_endpoint[22]; + + if (!endpoint) + { + static LONG lrpc_nameless_id; + DWORD process_id = GetCurrentProcessId(); + ULONG id = InterlockedIncrement(&lrpc_nameless_id); + snprintf(generated_endpoint, sizeof(generated_endpoint), + "LRPC%08x.%08x", process_id, id); + endpoint = generated_endpoint; + } r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, endpoint, NULL, NULL, NULL); @@ -305,12 +324,23 @@ static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection) return r; } -static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint) +static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) { static const char prefix[] = "\\\\."; RPC_STATUS r; LPSTR pname; RpcConnection *Connection; + char generated_endpoint[21]; + + if (!endpoint) + { + static LONG np_nameless_id; + DWORD process_id = GetCurrentProcessId(); + ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 ); + snprintf(generated_endpoint, sizeof(generated_endpoint), + "\\\\pipe\\\\%08x.%03x", process_id, id); + endpoint = generated_endpoint; + } r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, endpoint, NULL, NULL, NULL); @@ -340,7 +370,7 @@ static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np * new_npc->ovl[0] = old_npc->ovl[0]; new_npc->ovl[1] = old_npc->ovl[1]; old_npc->pipe = 0; - memset(&old_npc->ovl, 0, sizeof(old_npc->ovl)); + memset(&old_npc->ovl[0], 0, sizeof(old_npc->ovl)); old_npc->listening = FALSE; } @@ -392,11 +422,11 @@ static int rpcrt4_conn_np_read(RpcConnection *Connection, ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, &npc->ovl[0]); if ((!ret || !bytes_read) && (GetLastError() != ERROR_IO_PENDING)) break; - ret = GetOverlappedResult(npc->pipe, &npc->ovl[0], &bytes_read, TRUE); - if (!ret && (GetLastError() != ERROR_MORE_DATA)) + if (!ret && GetLastError() == ERROR_MORE_DATA) + ret = TRUE; + if (!ret || !bytes_read) break; - bytes_left -= bytes_read; buf += bytes_read; } @@ -417,11 +447,11 @@ static int rpcrt4_conn_np_write(RpcConnection *Connection, ret = WriteFile(npc->pipe, buf, bytes_left, &bytes_written, &npc->ovl[1]); if ((!ret || !bytes_written) && (GetLastError() != ERROR_IO_PENDING)) break; - ret = GetOverlappedResult(npc->pipe, &npc->ovl[1], &bytes_written, TRUE); - if (!ret && (GetLastError() != ERROR_MORE_DATA)) + if (!ret && GetLastError() == ERROR_MORE_DATA) + ret = TRUE; + if (!ret || !bytes_written) break; - bytes_left -= bytes_written; buf += bytes_written; } @@ -756,377 +786,10 @@ static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_d /**** ncacn_ip_tcp support ****/ -#ifdef HAVE_SOCKETPAIR - -typedef struct _RpcConnection_tcp -{ - RpcConnection common; - int sock; - int cancel_fds[2]; -} RpcConnection_tcp; - -static RpcConnection *rpcrt4_conn_tcp_alloc(void) -{ - RpcConnection_tcp *tcpc; - tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp)); - if (tcpc == NULL) - return NULL; - tcpc->sock = -1; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0) - { - ERR("socketpair() failed: %s\n", strerror(errno)); - HeapFree(GetProcessHeap(), 0, tcpc); - return NULL; - } - return &tcpc->common; -} - -static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) -{ - RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; - int sock; - int ret; - struct addrinfo *ai; - struct addrinfo *ai_cur; - struct addrinfo hints; - - TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); - - if (tcpc->sock != -1) - return RPC_S_OK; - - hints.ai_flags = 0; - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_addrlen = 0; - hints.ai_addr = NULL; - hints.ai_canonname = NULL; - hints.ai_next = NULL; - - ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai); - if (ret) - { - ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr, - Connection->Endpoint, gai_strerror(ret)); - return RPC_S_SERVER_UNAVAILABLE; - } - - for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) - { - int val; - - if (TRACE_ON(rpc)) - { - char host[256]; - char service[256]; - getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, - host, sizeof(host), service, sizeof(service), - NI_NUMERICHOST | NI_NUMERICSERV); - TRACE("trying %s:%s\n", host, service); - } - - sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); - if (sock == -1) - { - WARN("socket() failed: %s\n", strerror(errno)); - continue; - } - - if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen)) - { - WARN("connect() failed: %s\n", strerror(errno)); - closesocket(sock); - continue; - } - - /* RPC depends on having minimal latency so disable the Nagle algorithm */ - val = 1; - setsockopt(sock, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); - fcntl(sock, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ - - tcpc->sock = sock; - - freeaddrinfo(ai); - TRACE("connected\n"); - return RPC_S_OK; - } - - freeaddrinfo(ai); - ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint); - return RPC_S_SERVER_UNAVAILABLE; -} - -static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint) -{ - RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; - int sock; - int ret; - struct addrinfo *ai; - struct addrinfo *ai_cur; - struct addrinfo hints; - RpcConnection *first_connection = NULL; - - TRACE("(%p, %s)\n", protseq, endpoint); - - hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */; - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_addrlen = 0; - hints.ai_addr = NULL; - hints.ai_canonname = NULL; - hints.ai_next = NULL; - - ret = getaddrinfo(NULL, endpoint, &hints, &ai); - if (ret) - { - ERR("getaddrinfo for port %s failed: %s\n", endpoint, - gai_strerror(ret)); - if ((ret == EAI_SERVICE) || (ret == EAI_NONAME)) - return RPC_S_INVALID_ENDPOINT_FORMAT; - return RPC_S_CANT_CREATE_ENDPOINT; - } - - for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) - { - RpcConnection_tcp *tcpc; - RPC_STATUS create_status; - - if (TRACE_ON(rpc)) - { - char host[256]; - char service[256]; - getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, - host, sizeof(host), service, sizeof(service), - NI_NUMERICHOST | NI_NUMERICSERV); - TRACE("trying %s:%s\n", host, service); - } - - sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); - if (sock == -1) - { - WARN("socket() failed: %s\n", strerror(errno)); - status = RPC_S_CANT_CREATE_ENDPOINT; - continue; - } - - ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen); - if (ret < 0) - { - WARN("bind failed: %s\n", strerror(errno)); - closesocket(sock); - if (errno == EADDRINUSE) - status = RPC_S_DUPLICATE_ENDPOINT; - else - status = RPC_S_CANT_CREATE_ENDPOINT; - continue; - } - create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, - protseq->Protseq, NULL, - endpoint, NULL, NULL, NULL); - if (create_status != RPC_S_OK) - { - closesocket(sock); - status = create_status; - continue; - } - - tcpc->sock = sock; - ret = listen(sock, protseq->MaxCalls); - if (ret < 0) - { - WARN("listen failed: %s\n", strerror(errno)); - RPCRT4_DestroyConnection(&tcpc->common); - status = RPC_S_OUT_OF_RESOURCES; - continue; - } - /* need a non-blocking socket, otherwise accept() has a potential - * race-condition (poll() says it is readable, connection drops, - * and accept() blocks until the next connection comes...) - */ - ret = fcntl(sock, F_SETFL, O_NONBLOCK); - if (ret < 0) - { - WARN("couldn't make socket non-blocking, error %d\n", ret); - RPCRT4_DestroyConnection(&tcpc->common); - status = RPC_S_OUT_OF_RESOURCES; - continue; - } - - tcpc->common.Next = first_connection; - first_connection = &tcpc->common; - } - - freeaddrinfo(ai); - - /* if at least one connection was created for an endpoint then - * return success */ - if (first_connection) - { - RpcConnection *conn; - - /* find last element in list */ - for (conn = first_connection; conn->Next; conn = conn->Next) - ; - - EnterCriticalSection(&protseq->cs); - conn->Next = protseq->conn; - protseq->conn = first_connection; - LeaveCriticalSection(&protseq->cs); - - TRACE("listening on %s\n", endpoint); - return RPC_S_OK; - } - - ERR("couldn't listen on port %s\n", endpoint); - return status; -} - -static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) -{ - int ret; - struct sockaddr_in address; - socklen_t addrsize; - RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; - RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; - - addrsize = sizeof(address); - ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); - if (ret < 0) - { - ERR("Failed to accept a TCP connection: error %d\n", ret); - return RPC_S_OUT_OF_RESOURCES; - } - /* reset to blocking behaviour */ - fcntl(ret, F_SETFL, 0); - client->sock = ret; - TRACE("Accepted a new TCP connection\n"); - return RPC_S_OK; -} - -static int rpcrt4_conn_tcp_read(RpcConnection *Connection, - void *buffer, unsigned int count) -{ - RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; - 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 bytes_written = 0; - do - { - int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0); - 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) -{ - RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; - - TRACE("%d\n", tcpc->sock); - - if (tcpc->sock != -1) - closesocket(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 int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection) -{ - RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; - struct pollfd pfds[2]; - - TRACE("%p\n", Connection); - - 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; - } - - return 0; -} - -static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, - const char *networkaddr, - const char *endpoint) +static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + unsigned char tcp_protid, + const char *endpoint) { twr_tcp_floor_t *tcp_floor; twr_ipv4_floor_t *ipv4_floor; @@ -1146,7 +809,7 @@ static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, ipv4_floor = (twr_ipv4_floor_t *)tower_data; tcp_floor->count_lhs = sizeof(tcp_floor->protid); - tcp_floor->protid = EPM_PROTOCOL_TCP; + tcp_floor->protid = tcp_protid; tcp_floor->count_rhs = sizeof(tcp_floor->port); ipv4_floor->count_lhs = sizeof(ipv4_floor->protid); @@ -1191,10 +854,11 @@ static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, return size; } -static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, - size_t tower_size, - char **networkaddr, - char **endpoint) +static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + unsigned char tcp_protid, + char **endpoint) { const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data; const twr_ipv4_floor_t *ipv4_floor; @@ -1214,7 +878,7 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *to ipv4_floor = (const twr_ipv4_floor_t *)tower_data; if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) || - (tcp_floor->protid != EPM_PROTOCOL_TCP) || + (tcp_floor->protid != tcp_protid) || (tcp_floor->count_rhs != sizeof(tcp_floor->port)) || (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) || (ipv4_floor->protid != EPM_PROTOCOL_IP) || @@ -1259,6 +923,528 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *to return RPC_S_OK; } +typedef struct _RpcConnection_tcp +{ + RpcConnection common; + int sock; +#ifdef HAVE_SOCKETPAIR + int cancel_fds[2]; +#else + HANDLE sock_event; + HANDLE cancel_event; +#endif +} RpcConnection_tcp; + +#ifdef HAVE_SOCKETPAIR + +static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc) +{ + if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0) + { + ERR("socketpair() failed: %s\n", strerror(errno)); + return FALSE; + } + return TRUE; +} + +static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc) +{ + 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 FALSE; + } + if (pfds[1].revents & POLLIN) /* canceled */ + { + char dummy; + read(pfds[1].fd, &dummy, sizeof(dummy)); + return FALSE; + } + return TRUE; +} + +static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc) +{ + 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 FALSE; + } + return TRUE; +} + +static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc) +{ + char dummy = 1; + + write(tcpc->cancel_fds[1], &dummy, 1); +} + +static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc) +{ + close(tcpc->cancel_fds[0]); + close(tcpc->cancel_fds[1]); +} + +#else /* HAVE_SOCKETPAIR */ + +static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc) +{ + static BOOL wsa_inited; + if (!wsa_inited) + { + WSADATA wsadata; + WSAStartup(MAKEWORD(2, 2), &wsadata); + /* Note: WSAStartup can be called more than once so we don't bother with + * making accesses to wsa_inited thread-safe */ + wsa_inited = TRUE; + } + tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL); + tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!tcpc->sock_event || !tcpc->cancel_event) + { + ERR("event creation failed\n"); + if (tcpc->sock_event) CloseHandle(tcpc->sock_event); + return FALSE; + } + return TRUE; +} + +static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc) +{ + HANDLE wait_handles[2]; + DWORD res; + if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR) + { + ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); + return FALSE; + } + wait_handles[0] = tcpc->sock_event; + wait_handles[1] = tcpc->cancel_event; + res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE); + switch (res) + { + case WAIT_OBJECT_0: + return TRUE; + case WAIT_OBJECT_0 + 1: + return FALSE; + default: + ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); + return FALSE; + } +} + +static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc) +{ + DWORD res; + if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR) + { + ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); + return FALSE; + } + res = WaitForSingleObject(tcpc->sock_event, INFINITE); + switch (res) + { + case WAIT_OBJECT_0: + return TRUE; + default: + ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); + return FALSE; + } +} + +static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc) +{ + SetEvent(tcpc->cancel_event); +} + +static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc) +{ + CloseHandle(tcpc->sock_event); + CloseHandle(tcpc->cancel_event); +} + +#endif + +static RpcConnection *rpcrt4_conn_tcp_alloc(void) +{ + RpcConnection_tcp *tcpc; + tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp)); + if (tcpc == NULL) + return NULL; + tcpc->sock = -1; + if (!rpcrt4_sock_wait_init(tcpc)) + { + HeapFree(GetProcessHeap(), 0, tcpc); + return NULL; + } + return &tcpc->common; +} + +static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int sock; + int ret; + struct addrinfo *ai; + struct addrinfo *ai_cur; + struct addrinfo hints; + + TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); + + if (tcpc->sock != -1) + return RPC_S_OK; + + hints.ai_flags = 0; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai); + if (ret) + { + ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr, + Connection->Endpoint, gai_strerror(ret)); + return RPC_S_SERVER_UNAVAILABLE; + } + + for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) + { + int val; + u_long nonblocking; + + if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6) + { + TRACE("skipping non-IP/IPv6 address family\n"); + continue; + } + + if (TRACE_ON(rpc)) + { + char host[256]; + char service[256]; + getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + TRACE("trying %s:%s\n", host, service); + } + + sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); + if (sock == -1) + { + WARN("socket() failed: %s\n", strerror(errno)); + continue; + } + + if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen)) + { + WARN("connect() failed: %s\n", strerror(errno)); + closesocket(sock); + continue; + } + + /* RPC depends on having minimal latency so disable the Nagle algorithm */ + val = 1; + setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); + nonblocking = 1; + ioctlsocket(sock, FIONBIO, &nonblocking); + + tcpc->sock = sock; + + freeaddrinfo(ai); + TRACE("connected\n"); + return RPC_S_OK; + } + + freeaddrinfo(ai); + ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint); + return RPC_S_SERVER_UNAVAILABLE; +} + +static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) +{ + RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; + int sock; + int ret; + struct addrinfo *ai; + struct addrinfo *ai_cur; + struct addrinfo hints; + RpcConnection *first_connection = NULL; + + TRACE("(%p, %s)\n", protseq, endpoint); + + hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai); + if (ret) + { + ERR("getaddrinfo for port %s failed: %s\n", endpoint, + gai_strerror(ret)); + if ((ret == EAI_SERVICE) || (ret == EAI_NONAME)) + return RPC_S_INVALID_ENDPOINT_FORMAT; + return RPC_S_CANT_CREATE_ENDPOINT; + } + + for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) + { + RpcConnection_tcp *tcpc; + RPC_STATUS create_status; + struct sockaddr_storage sa; + socklen_t sa_len; + char service[NI_MAXSERV]; + u_long nonblocking; + + if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6) + { + TRACE("skipping non-IP/IPv6 address family\n"); + continue; + } + + if (TRACE_ON(rpc)) + { + char host[256]; + getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + TRACE("trying %s:%s\n", host, service); + } + + sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); + if (sock == -1) + { + WARN("socket() failed: %s\n", strerror(errno)); + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + + ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen); + if (ret < 0) + { + WARN("bind failed: %s\n", strerror(errno)); + closesocket(sock); + if (errno == EADDRINUSE) + status = RPC_S_DUPLICATE_ENDPOINT; + else + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + + sa_len = sizeof(sa); + if (getsockname(sock, (struct sockaddr *)&sa, &sa_len)) + { + WARN("getsockname() failed: %s\n", strerror(errno)); + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + + ret = getnameinfo((struct sockaddr *)&sa, sa_len, + NULL, 0, service, sizeof(service), + NI_NUMERICSERV); + if (ret) + { + WARN("getnameinfo failed: %s\n", gai_strerror(ret)); + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + + create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, + protseq->Protseq, NULL, + service, NULL, NULL, NULL); + if (create_status != RPC_S_OK) + { + closesocket(sock); + status = create_status; + continue; + } + + tcpc->sock = sock; + ret = listen(sock, protseq->MaxCalls); + if (ret < 0) + { + WARN("listen failed: %s\n", strerror(errno)); + RPCRT4_DestroyConnection(&tcpc->common); + status = RPC_S_OUT_OF_RESOURCES; + continue; + } + /* need a non-blocking socket, otherwise accept() has a potential + * race-condition (poll() says it is readable, connection drops, + * and accept() blocks until the next connection comes...) + */ + nonblocking = 1; + ret = ioctlsocket(sock, FIONBIO, &nonblocking); + if (ret < 0) + { + WARN("couldn't make socket non-blocking, error %d\n", ret); + RPCRT4_DestroyConnection(&tcpc->common); + status = RPC_S_OUT_OF_RESOURCES; + continue; + } + + tcpc->common.Next = first_connection; + first_connection = &tcpc->common; + + /* since IPv4 and IPv6 share the same port space, we only need one + * successful bind to listen for both */ + break; + } + + freeaddrinfo(ai); + + /* if at least one connection was created for an endpoint then + * return success */ + if (first_connection) + { + RpcConnection *conn; + + /* find last element in list */ + for (conn = first_connection; conn->Next; conn = conn->Next) + ; + + EnterCriticalSection(&protseq->cs); + conn->Next = protseq->conn; + protseq->conn = first_connection; + LeaveCriticalSection(&protseq->cs); + + TRACE("listening on %s\n", endpoint); + return RPC_S_OK; + } + + ERR("couldn't listen on port %s\n", endpoint); + return status; +} + +static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + int ret; + struct sockaddr_in address; + socklen_t addrsize; + RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; + RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; + u_long nonblocking; + + addrsize = sizeof(address); + ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); + if (ret < 0) + { + ERR("Failed to accept a TCP connection: error %d\n", ret); + return RPC_S_OUT_OF_RESOURCES; + } + nonblocking = 1; + ioctlsocket(ret, FIONBIO, &nonblocking); + client->sock = ret; + TRACE("Accepted a new TCP connection\n"); + return RPC_S_OK; +} + +static int rpcrt4_conn_tcp_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + 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 + { + if (!rpcrt4_sock_wait_for_recv(tcpc)) + 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 bytes_written = 0; + do + { + int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0); + if (r >= 0) + bytes_written += r; + else if (errno != EAGAIN) + return -1; + else + { + if (!rpcrt4_sock_wait_for_send(tcpc)) + 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) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + + TRACE("%d\n", tcpc->sock); + + if (tcpc->sock != -1) + closesocket(tcpc->sock); + tcpc->sock = -1; + rpcrt4_sock_wait_destroy(tcpc); + return 0; +} + +static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + TRACE("%p\n", Connection); + rpcrt4_sock_wait_cancel(tcpc); +} + +static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + + TRACE("%p\n", Connection); + + if (!rpcrt4_sock_wait_for_recv(tcpc)) + return -1; + return 0; +} + +static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, + EPM_PROTOCOL_TCP, endpoint); +} + +#ifdef HAVE_SOCKETPAIR + typedef struct _RpcServerProtseq_sock { RpcServerProtseq common; @@ -1398,8 +1584,1100 @@ static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq return 1; } +#else /* HAVE_SOCKETPAIR */ + +typedef struct _RpcServerProtseq_sock +{ + RpcServerProtseq common; + HANDLE mgr_event; +} RpcServerProtseq_sock; + +static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void) +{ + RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); + if (ps) + { + static BOOL wsa_inited; + if (!wsa_inited) + { + WSADATA wsadata; + WSAStartup(MAKEWORD(2, 2), &wsadata); + /* Note: WSAStartup can be called more than once so we don't bother with + * making accesses to wsa_inited thread-safe */ + wsa_inited = TRUE; + } + ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); + } + return &ps->common; +} + +static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq) +{ + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + SetEvent(sockps->mgr_event); +} + +static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) +{ + HANDLE *objs = prev_array; + RpcConnection_tcp *conn; + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + + EnterCriticalSection(&protseq->cs); + + /* open and count connections */ + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) + { + if (conn->sock != -1) + (*count)++; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + + /* make array of connections */ + if (objs) + objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); + else + objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); + if (!objs) + { + ERR("couldn't allocate objs\n"); + LeaveCriticalSection(&protseq->cs); + return NULL; + } + + objs[0] = sockps->mgr_event; + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) + { + if (conn->sock != -1) + { + int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT); + if (res == SOCKET_ERROR) + ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); + else + { + objs[*count] = conn->sock_event; + (*count)++; + } + } + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + LeaveCriticalSection(&protseq->cs); + return objs; +} + +static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array) +{ + HeapFree(GetProcessHeap(), 0, array); +} + +static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) +{ + HANDLE b_handle; + HANDLE *objs = wait_array; + DWORD res; + RpcConnection *cconn; + RpcConnection_tcp *conn; + + if (!objs) + return -1; + + 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) + { + ERR("wait failed with error %d\n", GetLastError()); + return -1; + } + else + { + b_handle = objs[res - WAIT_OBJECT_0]; + /* find which connection got a RPC */ + EnterCriticalSection(&protseq->cs); + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) + { + if (b_handle == conn->sock_event) break; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + cconn = NULL; + if (conn) + RPCRT4_SpawnConnection(&cconn, &conn->common); + else + ERR("failed to locate connection for handle %p\n", b_handle); + LeaveCriticalSection(&protseq->cs); + if (cconn) + { + RPCRT4_new_client(cconn); + return 1; + } + else return -1; + } +} + #endif /* HAVE_SOCKETPAIR */ +static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, + networkaddr, EPM_PROTOCOL_TCP, + endpoint); +} + +/**** ncacn_http support ****/ +#if 0 +/* 60 seconds is the period native uses */ +#define HTTP_IDLE_TIME 60000 + +/* reference counted to avoid a race between a cancelled call's connection + * being destroyed and the asynchronous InternetReadFileEx call being + * completed */ +typedef struct _RpcHttpAsyncData +{ + LONG refs; + HANDLE completion_event; + INTERNET_BUFFERSA inet_buffers; + void *destination_buffer; /* the address that inet_buffers.lpvBuffer will be + * copied into when the call completes */ + CRITICAL_SECTION cs; +} RpcHttpAsyncData; + +static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data) +{ + return InterlockedIncrement(&data->refs); +} + +static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data) +{ + ULONG refs = InterlockedDecrement(&data->refs); + if (!refs) + { + TRACE("destroying async data %p\n", data); + CloseHandle(data->completion_event); + HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer); + DeleteCriticalSection(&data->cs); + HeapFree(GetProcessHeap(), 0, data); + } + return refs; +} + +typedef struct _RpcConnection_http +{ + RpcConnection common; + HINTERNET app_info; + HINTERNET session; + HINTERNET in_request; + HINTERNET out_request; + HANDLE timer_cancelled; + HANDLE cancel_event; + DWORD last_sent_time; + ULONG bytes_received; + ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */ + ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */ + UUID connection_uuid; + UUID in_pipe_uuid; + UUID out_pipe_uuid; + RpcHttpAsyncData *async_data; +} RpcConnection_http; + +static RpcConnection *rpcrt4_ncacn_http_alloc(void) +{ + RpcConnection_http *httpc; + httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc)); + if (!httpc) return NULL; + httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData)); + if (!httpc->async_data) + { + HeapFree(GetProcessHeap(), 0, httpc); + return NULL; + } + TRACE("async data = %p\n", httpc->async_data); + httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); + httpc->async_data->refs = 1; + httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSA); + httpc->async_data->inet_buffers.lpvBuffer = NULL; + httpc->async_data->destination_buffer = NULL; + InitializeCriticalSection(&httpc->async_data->cs); + return &httpc->common; +} + +typedef struct _HttpTimerThreadData +{ + PVOID timer_param; + DWORD *last_sent_time; + HANDLE timer_cancelled; +} HttpTimerThreadData; + +static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy) +{ + HINTERNET in_request = param; + RpcPktHdr *idle_pkt; + + idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001, + 0, 0); + if (idle_pkt) + { + DWORD bytes_written; + InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written); + RPCRT4_FreeHeader(idle_pkt); + } +} + +static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time) +{ + DWORD cur_time = GetTickCount(); + DWORD cached_last_sent_time = *last_sent_time; + return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time); +} + +static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param) +{ + HttpTimerThreadData *data_in = param; + HttpTimerThreadData data; + DWORD timeout; + + data = *data_in; + HeapFree(GetProcessHeap(), 0, data_in); + + for (timeout = HTTP_IDLE_TIME; + WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT; + timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time)) + { + /* are we too soon after last send? */ + if (GetTickCount() - HTTP_IDLE_TIME < *data.last_sent_time) + continue; + rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE); + } + + CloseHandle(data.timer_cancelled); + return 0; +} + +static VOID WINAPI rpcrt4_http_internet_callback( + HINTERNET hInternet, + DWORD_PTR dwContext, + DWORD dwInternetStatus, + LPVOID lpvStatusInformation, + DWORD dwStatusInformationLength) +{ + RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext; + + switch (dwInternetStatus) + { + case INTERNET_STATUS_REQUEST_COMPLETE: + TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n"); + if (async_data) + { + if (async_data->inet_buffers.lpvBuffer) + { + EnterCriticalSection(&async_data->cs); + if (async_data->destination_buffer) + { + memcpy(async_data->destination_buffer, + async_data->inet_buffers.lpvBuffer, + async_data->inet_buffers.dwBufferLength); + async_data->destination_buffer = NULL; + } + LeaveCriticalSection(&async_data->cs); + } + HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer); + async_data->inet_buffers.lpvBuffer = NULL; + SetEvent(async_data->completion_event); + RpcHttpAsyncData_Release(async_data); + } + break; + } +} + +static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor) +{ + BOOL ret; + DWORD status_code; + DWORD size; + DWORD index; + WCHAR buf[32]; + WCHAR *status_text = buf; + TRACE("\n"); + + index = 0; + size = sizeof(status_code); + ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index); + if (!ret) + return GetLastError(); + if (status_code < 400) + return RPC_S_OK; + index = 0; + size = sizeof(buf); + ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); + if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + status_text = HeapAlloc(GetProcessHeap(), 0, size); + ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); + } + + ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : ""); + if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text); + + if (status_code == HTTP_STATUS_DENIED) + return ERROR_ACCESS_DENIED; + return RPC_S_SERVER_UNAVAILABLE; +} + +static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc) +{ + static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0}; + LPWSTR proxy = NULL; + LPWSTR user = NULL; + LPWSTR password = NULL; + LPWSTR servername = NULL; + const WCHAR *option; + INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; /* use default port */ + + if (httpc->common.QOS && + (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)) + { + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials; + if (http_cred->TransportCredentials) + { + WCHAR *p; + const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials; + ULONG len = cred->DomainLength + 1 + cred->UserLength; + user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); + if (!user) + return RPC_S_OUT_OF_RESOURCES; + p = user; + if (cred->DomainLength) + { + memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR)); + p += cred->DomainLength; + *p = '\\'; + p++; + } + memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR)); + p[cred->UserLength] = 0; + + password = RPCRT4_strndupW(cred->Password, cred->PasswordLength); + } + } + + for (option = httpc->common.NetworkOptions; option; + option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL)) + { + static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0}; + static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0}; + + if (!strncmpiW(option, wszRpcProxy, sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1)) + { + const WCHAR *value_start = option + sizeof(wszRpcProxy)/sizeof(wszRpcProxy[0])-1; + const WCHAR *value_end; + const WCHAR *p; + + value_end = strchrW(option, ','); + if (!value_end) + value_end = value_start + strlenW(value_start); + for (p = value_start; p < value_end; p++) + if (*p == ':') + { + port = atoiW(p+1); + value_end = p; + break; + } + TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); + servername = RPCRT4_strndupW(value_start, value_end-value_start); + } + else if (!strncmpiW(option, wszHttpProxy, sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1)) + { + const WCHAR *value_start = option + sizeof(wszHttpProxy)/sizeof(wszHttpProxy[0])-1; + const WCHAR *value_end; + + value_end = strchrW(option, ','); + if (!value_end) + value_end = value_start + strlenW(value_start); + TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); + proxy = RPCRT4_strndupW(value_start, value_end-value_start); + } + else + FIXME("unhandled option %s\n", debugstr_w(option)); + } + + httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG, + NULL, NULL, INTERNET_FLAG_ASYNC); + if (!httpc->app_info) + { + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, user); + ERR("InternetOpenW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback); + + /* if no RpcProxy option specified, set the HTTP server address to the + * RPC server address */ + if (!servername) + { + servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR)); + if (!servername) + { + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, user); + return RPC_S_OUT_OF_RESOURCES; + } + MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1); + } + + httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password, + INTERNET_SERVICE_HTTP, 0, 0); + + HeapFree(GetProcessHeap(), 0, password); + HeapFree(GetProcessHeap(), 0, user); + HeapFree(GetProcessHeap(), 0, servername); + + if (!httpc->session) + { + ERR("InternetConnectW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + return RPC_S_OK; +} + +/* prepare the in pipe for use by RPC packets */ +static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, + const UUID *connection_uuid, + const UUID *in_pipe_uuid, + const UUID *association_uuid) +{ + BYTE packet[44]; + BOOL ret; + RPC_STATUS status; + RpcPktHdr *hdr; + INTERNET_BUFFERSW buffers_in; + DWORD bytes_read, bytes_written; + + /* prepare in pipe */ + ResetEvent(async_data->completion_event); + RpcHttpAsyncData_AddRef(async_data); + ret = HttpSendRequestW(in_request, NULL, 0, NULL, 0); + if (!ret) + { + if (GetLastError() == ERROR_IO_PENDING) + WaitForSingleObject(async_data->completion_event, INFINITE); + else + { + RpcHttpAsyncData_Release(async_data); + ERR("HttpSendRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + } + status = rpcrt4_http_check_response(in_request); + if (status != RPC_S_OK) return status; + + InternetReadFile(in_request, packet, 20, &bytes_read); + /* FIXME: do something with retrieved data */ + + memset(&buffers_in, 0, sizeof(buffers_in)); + buffers_in.dwStructSize = sizeof(buffers_in); + /* FIXME: get this from the registry */ + buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */ + ResetEvent(async_data->completion_event); + RpcHttpAsyncData_AddRef(async_data); + ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0); + if (!ret) + { + if (GetLastError() == ERROR_IO_PENDING) + WaitForSingleObject(async_data->completion_event, INFINITE); + else + { + RpcHttpAsyncData_Release(async_data); + ERR("HttpSendRequestExW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + } + + TRACE("sending HTTP connect header to server\n"); + hdr = RPCRT4_BuildHttpConnectHeader(0, FALSE, connection_uuid, in_pipe_uuid, association_uuid); + if (!hdr) return RPC_S_OUT_OF_RESOURCES; + ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written); + RPCRT4_FreeHeader(hdr); + if (!ret) + { + ERR("InternetWriteFile failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcPktHdr *hdr, BYTE **data) +{ + BOOL ret; + DWORD bytes_read; + unsigned short data_len; + + ret = InternetReadFile(request, hdr, sizeof(hdr->common), &bytes_read); + if (!ret) + return RPC_S_SERVER_UNAVAILABLE; + if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http)) + { + ERR("wrong packet type received %d or wrong frag_len %d\n", + hdr->common.ptype, hdr->common.frag_len); + return RPC_S_PROTOCOL_ERROR; + } + + ret = InternetReadFile(request, &hdr->common + 1, sizeof(hdr->http) - sizeof(hdr->common), &bytes_read); + if (!ret) + return RPC_S_SERVER_UNAVAILABLE; + + data_len = hdr->common.frag_len - sizeof(hdr->http); + if (data_len) + { + *data = HeapAlloc(GetProcessHeap(), 0, data_len); + if (!*data) + return RPC_S_OUT_OF_RESOURCES; + ret = InternetReadFile(request, *data, data_len, &bytes_read); + if (!ret) + { + HeapFree(GetProcessHeap(), 0, *data); + return RPC_S_SERVER_UNAVAILABLE; + } + } + else + *data = NULL; + + if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len)) + { + ERR("invalid http packet\n"); + return RPC_S_PROTOCOL_ERROR; + } + + return RPC_S_OK; +} + +/* prepare the out pipe for use by RPC packets */ +static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, + RpcHttpAsyncData *async_data, + const UUID *connection_uuid, + const UUID *out_pipe_uuid, + ULONG *flow_control_increment) +{ + BYTE packet[20]; + BOOL ret; + RPC_STATUS status; + RpcPktHdr *hdr; + DWORD bytes_read; + BYTE *data_from_server; + RpcPktHdr pkt_from_server; + ULONG field1, field3; + + ResetEvent(async_data->completion_event); + RpcHttpAsyncData_AddRef(async_data); + ret = HttpSendRequestW(out_request, NULL, 0, NULL, 0); + if (!ret) + { + if (GetLastError() == ERROR_IO_PENDING) + WaitForSingleObject(async_data->completion_event, INFINITE); + else + { + RpcHttpAsyncData_Release(async_data); + ERR("HttpSendRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + } + status = rpcrt4_http_check_response(out_request); + if (status != RPC_S_OK) return status; + + InternetReadFile(out_request, packet, 20, &bytes_read); + /* FIXME: do something with retrieved data */ + + hdr = RPCRT4_BuildHttpConnectHeader(0, TRUE, connection_uuid, out_pipe_uuid, NULL); + if (!hdr) return RPC_S_OUT_OF_RESOURCES; + ResetEvent(async_data->completion_event); + RpcHttpAsyncData_AddRef(async_data); + ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len); + if (!ret) + { + if (GetLastError() == ERROR_IO_PENDING) + WaitForSingleObject(async_data->completion_event, INFINITE); + else + { + RpcHttpAsyncData_Release(async_data); + ERR("HttpSendRequestW failed with error %d\n", GetLastError()); + RPCRT4_FreeHeader(hdr); + return RPC_S_SERVER_UNAVAILABLE; + } + } + RPCRT4_FreeHeader(hdr); + status = rpcrt4_http_check_response(out_request); + if (status != RPC_S_OK) return status; + + status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server, + &data_from_server); + if (status != RPC_S_OK) return status; + status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server, + &field1); + HeapFree(GetProcessHeap(), 0, data_from_server); + if (status != RPC_S_OK) return status; + TRACE("received (%d) from first prepare header\n", field1); + + status = rpcrt4_http_read_http_packet(out_request, &pkt_from_server, + &data_from_server); + if (status != RPC_S_OK) return status; + status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server, + &field1, flow_control_increment, + &field3); + HeapFree(GetProcessHeap(), 0, data_from_server); + if (status != RPC_S_OK) return status; + TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3); + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) +{ + RpcConnection_http *httpc = (RpcConnection_http *)Connection; + static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0}; + static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0}; + static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0}; + static const WCHAR wszColon[] = {':',0}; + static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0}; + LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL }; + WCHAR *url; + RPC_STATUS status; + BOOL secure; + HttpTimerThreadData *timer_data; + HANDLE thread; + + TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); + + if (Connection->server) + { + ERR("ncacn_http servers not supported yet\n"); + return RPC_S_SERVER_UNAVAILABLE; + } + + if (httpc->in_request) + return RPC_S_OK; + + httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL); + + status = UuidCreate(&httpc->connection_uuid); + status = UuidCreate(&httpc->in_pipe_uuid); + status = UuidCreate(&httpc->out_pipe_uuid); + + status = rpcrt4_http_internet_connect(httpc); + if (status != RPC_S_OK) + return status; + + url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR)); + if (!url) + return RPC_S_OUT_OF_MEMORY; + memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix)); + MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+sizeof(wszRpcProxyPrefix)/sizeof(wszRpcProxyPrefix[0])-1, strlen(Connection->NetworkAddr)+1); + strcatW(url, wszColon); + MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1); + + secure = httpc->common.QOS && + (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) && + (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL); + + httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, + wszAcceptTypes, + (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE, + (DWORD_PTR)httpc->async_data); + if (!httpc->in_request) + { + ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, + wszAcceptTypes, + (secure ? INTERNET_FLAG_SECURE : 0)|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_PRAGMA_NOCACHE, + (DWORD_PTR)httpc->async_data); + if (!httpc->out_request) + { + ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + + status = rpcrt4_http_prepare_in_pipe(httpc->in_request, + httpc->async_data, + &httpc->connection_uuid, + &httpc->in_pipe_uuid, + &Connection->assoc->http_uuid); + if (status != RPC_S_OK) + return status; + + status = rpcrt4_http_prepare_out_pipe(httpc->out_request, + httpc->async_data, + &httpc->connection_uuid, + &httpc->out_pipe_uuid, + &httpc->flow_control_increment); + if (status != RPC_S_OK) + return status; + + httpc->flow_control_mark = httpc->flow_control_increment / 2; + httpc->last_sent_time = GetTickCount(); + httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL); + + timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data)); + if (!timer_data) + return ERROR_OUTOFMEMORY; + timer_data->timer_param = httpc->in_request; + timer_data->last_sent_time = &httpc->last_sent_time; + timer_data->timer_cancelled = httpc->timer_cancelled; + /* FIXME: should use CreateTimerQueueTimer when implemented */ + thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL); + if (!thread) + { + HeapFree(GetProcessHeap(), 0, timer_data); + return GetLastError(); + } + CloseHandle(thread); + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + assert(0); + return RPC_S_SERVER_UNAVAILABLE; +} + +static int rpcrt4_ncacn_http_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + char *buf = buffer; + BOOL ret = TRUE; + unsigned int bytes_left = count; + + ResetEvent(httpc->async_data->completion_event); + while (bytes_left) + { + RpcHttpAsyncData_AddRef(httpc->async_data); + httpc->async_data->inet_buffers.dwBufferLength = bytes_left; + httpc->async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, bytes_left); + httpc->async_data->destination_buffer = buf; + ret = InternetReadFileExA(httpc->out_request, &httpc->async_data->inet_buffers, IRF_ASYNC, 0); + if (ret) + { + /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our + * async ref now */ + RpcHttpAsyncData_Release(httpc->async_data); + memcpy(buf, httpc->async_data->inet_buffers.lpvBuffer, + httpc->async_data->inet_buffers.dwBufferLength); + HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer); + httpc->async_data->inet_buffers.lpvBuffer = NULL; + httpc->async_data->destination_buffer = NULL; + } + else + { + if (GetLastError() == ERROR_IO_PENDING) + { + HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event }; + DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT); + if (result == WAIT_OBJECT_0) + ret = TRUE; + else + { + TRACE("call cancelled\n"); + EnterCriticalSection(&httpc->async_data->cs); + httpc->async_data->destination_buffer = NULL; + LeaveCriticalSection(&httpc->async_data->cs); + break; + } + } + else + { + HeapFree(GetProcessHeap(), 0, httpc->async_data->inet_buffers.lpvBuffer); + httpc->async_data->inet_buffers.lpvBuffer = NULL; + httpc->async_data->destination_buffer = NULL; + RpcHttpAsyncData_Release(httpc->async_data); + break; + } + } + if (!httpc->async_data->inet_buffers.dwBufferLength) + break; + bytes_left -= httpc->async_data->inet_buffers.dwBufferLength; + buf += httpc->async_data->inet_buffers.dwBufferLength; + } + TRACE("%p %p %u -> %s\n", httpc->out_request, buffer, count, ret ? "TRUE" : "FALSE"); + return ret ? count : -1; +} + +static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + RPC_STATUS status; + DWORD hdr_length; + LONG dwRead; + RpcPktCommonHdr common_hdr; + + *Header = NULL; + + TRACE("(%p, %p, %p)\n", Connection, Header, Payload); + +again: + /* read packet common header */ + dwRead = rpcrt4_ncacn_http_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; + goto fail; + } + if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) || + !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0"))) + { + FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr)); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + status = RPCRT4_ValidateCommonHeader(&common_hdr); + if (status != RPC_S_OK) goto fail; + + hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); + if (hdr_length == 0) { + WARN("header length == 0\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); + if (!*Header) + { + status = RPC_S_OUT_OF_RESOURCES; + goto fail; + } + memcpy(*Header, &common_hdr, sizeof(common_hdr)); + + /* read the rest of packet header */ + dwRead = rpcrt4_ncacn_http_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; + goto fail; + } + + if (common_hdr.frag_len - hdr_length) + { + *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length); + if (!*Payload) + { + status = RPC_S_OUT_OF_RESOURCES; + goto fail; + } + + dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length); + if (dwRead != common_hdr.frag_len - hdr_length) + { + WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + else + *Payload = NULL; + + if ((*Header)->common.ptype == PKT_HTTP) + { + if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length)) + { + ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + if ((*Header)->http.flags == 0x0001) + { + TRACE("http idle packet, waiting for real packet\n"); + if ((*Header)->http.num_data_items != 0) + { + ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + else if ((*Header)->http.flags == 0x0002) + { + ULONG bytes_transmitted; + ULONG flow_control_increment; + UUID pipe_uuid; + status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload, + Connection->server, + &bytes_transmitted, + &flow_control_increment, + &pipe_uuid); + if (status != RPC_S_OK) + goto fail; + TRACE("received http flow control header (0x%x, 0x%x, %s)\n", + bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid)); + /* FIXME: do something with parsed data */ + } + else + { + FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + RPCRT4_FreeHeader(*Header); + *Header = NULL; + HeapFree(GetProcessHeap(), 0, *Payload); + *Payload = NULL; + goto again; + } + + /* success */ + status = RPC_S_OK; + + httpc->bytes_received += common_hdr.frag_len; + + TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received); + + if (httpc->bytes_received > httpc->flow_control_mark) + { + RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server, + httpc->bytes_received, + httpc->flow_control_increment, + &httpc->out_pipe_uuid); + if (hdr) + { + DWORD bytes_written; + BOOL ret2; + TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received); + ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written); + RPCRT4_FreeHeader(hdr); + if (ret2) + httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2; + } + } + +fail: + if (status != RPC_S_OK) { + RPCRT4_FreeHeader(*Header); + *Header = NULL; + HeapFree(GetProcessHeap(), 0, *Payload); + *Payload = NULL; + } + return status; +} + +static int rpcrt4_ncacn_http_write(RpcConnection *Connection, + const void *buffer, unsigned int count) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + DWORD bytes_written; + BOOL ret; + + httpc->last_sent_time = ~0U; /* disable idle packet sending */ + ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written); + httpc->last_sent_time = GetTickCount(); + TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE"); + return ret ? bytes_written : -1; +} + +static int rpcrt4_ncacn_http_close(RpcConnection *Connection) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + + TRACE("\n"); + + SetEvent(httpc->timer_cancelled); + if (httpc->in_request) + InternetCloseHandle(httpc->in_request); + httpc->in_request = NULL; + if (httpc->out_request) + InternetCloseHandle(httpc->out_request); + httpc->out_request = NULL; + if (httpc->app_info) + InternetCloseHandle(httpc->app_info); + httpc->app_info = NULL; + if (httpc->session) + InternetCloseHandle(httpc->session); + httpc->session = NULL; + RpcHttpAsyncData_Release(httpc->async_data); + if (httpc->cancel_event) + CloseHandle(httpc->cancel_event); + + return 0; +} + +static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection) +{ + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + + SetEvent(httpc->cancel_event); +} + +static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection) +{ + BOOL ret; + RpcConnection_http *httpc = (RpcConnection_http *) Connection; + + RpcHttpAsyncData_AddRef(httpc->async_data); + ret = InternetQueryDataAvailable(httpc->out_request, + &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0); + if (ret) + { + /* INTERNET_STATUS_REQUEST_COMPLETED won't be sent, so release our + * async ref now */ + RpcHttpAsyncData_Release(httpc->async_data); + } + else + { + if (GetLastError() == ERROR_IO_PENDING) + { + HANDLE handles[2] = { httpc->async_data->completion_event, httpc->cancel_event }; + DWORD result = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT); + if (result != WAIT_OBJECT_0) + { + TRACE("call cancelled\n"); + return -1; + } + } + else + { + RpcHttpAsyncData_Release(httpc->async_data); + return -1; + } + } + + /* success */ + return 0; +} + +static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, + EPM_PROTOCOL_HTTP, endpoint); +} + +static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, + networkaddr, EPM_PROTOCOL_HTTP, + endpoint); +} +#endif static const struct connection_ops conn_protseq_list[] = { { "ncacn_np", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB }, @@ -1413,6 +2691,7 @@ static const struct connection_ops conn_protseq_list[] = { rpcrt4_conn_np_wait_for_incoming_data, rpcrt4_ncacn_np_get_top_of_tower, rpcrt4_ncacn_np_parse_top_of_tower, + NULL, }, { "ncalrpc", { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, @@ -1426,8 +2705,8 @@ static const struct connection_ops conn_protseq_list[] = { rpcrt4_conn_np_wait_for_incoming_data, rpcrt4_ncalrpc_get_top_of_tower, rpcrt4_ncalrpc_parse_top_of_tower, + NULL, }, -#ifdef HAVE_SOCKETPAIR { "ncacn_ip_tcp", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, rpcrt4_conn_tcp_alloc, @@ -1440,7 +2719,23 @@ static const struct connection_ops conn_protseq_list[] = { rpcrt4_conn_tcp_wait_for_incoming_data, rpcrt4_ncacn_ip_tcp_get_top_of_tower, rpcrt4_ncacn_ip_tcp_parse_top_of_tower, - } + NULL, + }, +#if 0 + { "ncacn_http", + { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP }, + rpcrt4_ncacn_http_alloc, + rpcrt4_ncacn_http_open, + rpcrt4_ncacn_http_handoff, + rpcrt4_ncacn_http_read, + rpcrt4_ncacn_http_write, + rpcrt4_ncacn_http_close, + rpcrt4_ncacn_http_cancel_call, + rpcrt4_ncacn_http_wait_for_incoming_data, + rpcrt4_ncacn_http_get_top_of_tower, + rpcrt4_ncacn_http_parse_top_of_tower, + rpcrt4_ncacn_http_receive_fragment, + }, #endif }; @@ -1465,7 +2760,6 @@ static const struct protseq_ops protseq_list[] = rpcrt4_protseq_np_wait_for_new_connection, rpcrt4_protseq_ncalrpc_open_endpoint, }, -#ifdef HAVE_SOCKETPAIR { "ncacn_ip_tcp", rpcrt4_protseq_sock_alloc, @@ -1475,7 +2769,6 @@ static const struct protseq_ops protseq_list[] = rpcrt4_protseq_sock_wait_for_new_connection, rpcrt4_protseq_ncacn_ip_tcp_open_endpoint, }, -#endif }; #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0])) @@ -1524,6 +2817,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS) { + static LONG next_id; const struct connection_ops *ops; RpcConnection* NewConnection; @@ -1551,6 +2845,7 @@ RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, NewConnection->attr = 0; if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo); NewConnection->AuthInfo = AuthInfo; + NewConnection->auth_context_id = InterlockedIncrement( &next_id ); NewConnection->encryption_auth_len = 0; NewConnection->signature_auth_len = 0; if (QOS) RpcQualityOfService_AddRef(QOS); diff --git a/reactos/dll/win32/rpcrt4/rpcrt4.rbuild b/reactos/dll/win32/rpcrt4/rpcrt4.rbuild index 67f05aebcfb..59f9fe29ea4 100644 --- a/reactos/dll/win32/rpcrt4/rpcrt4.rbuild +++ b/reactos/dll/win32/rpcrt4/rpcrt4.rbuild @@ -14,6 +14,7 @@ user32 advapi32 secur32 + iphlpapi ws2_32 ntdll diff --git a/reactos/dll/win32/rpcrt4/rpcrt4.spec b/reactos/dll/win32/rpcrt4/rpcrt4.spec index 4550889f62a..0a047691822 100644 --- a/reactos/dll/win32/rpcrt4/rpcrt4.spec +++ b/reactos/dll/win32/rpcrt4/rpcrt4.spec @@ -116,8 +116,9 @@ @ stdcall NDRSContextUnmarshallEx(ptr ptr ptr) @ stub NDRcopy @ stdcall NdrAllocate(ptr long) -@ stub NdrAsyncClientCall +@ varargs NdrAsyncClientCall(ptr ptr) @ stub NdrAsyncServerCall +@ stdcall NdrAsyncStubCall(ptr ptr ptr ptr) @ stdcall NdrByteCountPointerBufferSize(ptr ptr ptr) @ stdcall NdrByteCountPointerFree(ptr ptr ptr) @ stdcall NdrByteCountPointerMarshall(ptr ptr ptr) @@ -370,7 +371,7 @@ @ stdcall RpcEpRegisterA(ptr ptr ptr str) @ stub RpcEpRegisterNoReplaceA @ stub RpcEpRegisterNoReplaceW -@ stub RpcEpRegisterW +@ stdcall RpcEpRegisterW(ptr ptr ptr wstr) @ stdcall RpcEpResolveBinding(ptr ptr) @ stdcall RpcEpUnregister(ptr ptr ptr) @ stub RpcErrorAddRecord # wxp diff --git a/reactos/dll/win32/rpcrt4/rpcrt4_main.c b/reactos/dll/win32/rpcrt4/rpcrt4_main.c index 537a00537bc..2cc7429bf29 100644 --- a/reactos/dll/win32/rpcrt4/rpcrt4_main.c +++ b/reactos/dll/win32/rpcrt4/rpcrt4_main.c @@ -43,8 +43,10 @@ #include "winuser.h" #include "winnt.h" #include "winternl.h" -#include "iptypes.h" -#include "iphlpapi.h" +#define _NTDEF_ +typedef NTSTATUS *PNTSTATUS; +#include "ntsecapi.h" +#undef _NTDEF_ #include "wine/unicode.h" #include "rpc.h" @@ -53,6 +55,7 @@ #include "rpcproxy.h" #include "rpc_binding.h" +#include "rpc_server.h" #include "wine/debug.h" @@ -60,15 +63,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc); static UUID uuid_nil; -static CRITICAL_SECTION uuid_cs; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &uuid_cs, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": uuid_cs") } -}; -static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; - static CRITICAL_SECTION threaddata_cs; static CRITICAL_SECTION_DEBUG threaddata_cs_debug = { @@ -135,6 +129,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) break; case DLL_PROCESS_DETACH: + RPCRT4_destroy_all_protseqs(); break; } @@ -280,61 +275,6 @@ RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid) return RPC_S_OK; } -/* Number of 100ns ticks per clock tick. To be safe, assume that the clock - resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ -#define TICKS_PER_CLOCK_TICK 1000 -#define SECSPERDAY 86400 -#define TICKSPERSEC 10000000 -/* UUID system time starts at October 15, 1582 */ -#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) -#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) - -static void RPC_UuidGetSystemTime(ULONGLONG *time) -{ - FILETIME ft; - - GetSystemTimeAsFileTime(&ft); - - *time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime; - *time += TICKS_15_OCT_1582_TO_1601; -} - -/* Assume that a hardware address is at least 6 bytes long */ -#define ADDRESS_BYTES_NEEDED 6 - -static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) -{ - int i; - DWORD status = RPC_S_OK; - - ULONG buflen = sizeof(IP_ADAPTER_INFO); - PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - - if (GetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { - HeapFree(GetProcessHeap(), 0, adapter); - adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - } - - if (GetAdaptersInfo(adapter, &buflen) == NO_ERROR) { - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = adapter->Address[i]; - } - } - /* We can't get a hardware address, just use random numbers. - Set the multicast bit to prevent conflicts with real cards. */ - else { - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = rand() & 0xff; - } - - address[0] |= 0x01; - status = RPC_S_UUID_LOCAL_ONLY; - } - - HeapFree(GetProcessHeap(), 0, adapter); - return status; -} - /************************************************************************* * UuidCreate [RPCRT4.@] * @@ -345,83 +285,26 @@ static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) * RPC_S_OK if successful. * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. * - * FIXME: No compensation for changes across reloading - * this dll or across reboots (e.g. clock going - * backwards and swapped network cards). The RFC - * suggests using NVRAM for storing persistent - * values. + * NOTES + * + * Follows RFC 4122, section 4.4 (Algorithms for Creating a UUID from + * Truly Random or Pseudo-Random Numbers) */ RPC_STATUS WINAPI UuidCreate(UUID *Uuid) { - static int initialised, count; - - ULONGLONG time; - static ULONGLONG timelast; - static WORD sequence; - - static DWORD status; - static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH]; - - EnterCriticalSection(&uuid_cs); - - if (!initialised) { - RPC_UuidGetSystemTime(&timelast); - count = TICKS_PER_CLOCK_TICK; - - sequence = ((rand() & 0xff) << 8) + (rand() & 0xff); - sequence &= 0x1fff; - - status = RPC_UuidGetNodeAddress(address); - initialised = 1; - } - - /* Generate time element of the UUID. Account for going faster - than our clock as well as the clock going backwards. */ - while (1) { - RPC_UuidGetSystemTime(&time); - if (time > timelast) { - count = 0; - break; - } - if (time < timelast) { - sequence = (sequence + 1) & 0x1fff; - count = 0; - break; - } - if (count < TICKS_PER_CLOCK_TICK) { - count++; - break; - } - } - - timelast = time; - time += count; - - /* Pack the information into the UUID structure. */ - - Uuid->Data1 = (unsigned long)(time & 0xffffffff); - Uuid->Data2 = (unsigned short)((time >> 32) & 0xffff); - Uuid->Data3 = (unsigned short)((time >> 48) & 0x0fff); - - /* This is a version 1 UUID */ - Uuid->Data3 |= (1 << 12); - - Uuid->Data4[0] = sequence & 0xff; - Uuid->Data4[1] = (sequence & 0x3f00) >> 8; - Uuid->Data4[1] |= 0x80; - - Uuid->Data4[2] = address[0]; - Uuid->Data4[3] = address[1]; - Uuid->Data4[4] = address[2]; - Uuid->Data4[5] = address[3]; - Uuid->Data4[6] = address[4]; - Uuid->Data4[7] = address[5]; - - LeaveCriticalSection(&uuid_cs); + RtlGenRandom(Uuid, sizeof(*Uuid)); + /* Clear the version bits and set the version (4) */ + Uuid->Data3 &= 0x0fff; + Uuid->Data3 |= (4 << 12); + /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as + * specified in RFC 4122, section 4.4. + */ + Uuid->Data4[0] &= 0x3f; + Uuid->Data4[0] |= 0x80; TRACE("%s\n", debugstr_guid(Uuid)); - return status; + return RPC_S_OK; } /************************************************************************* diff --git a/reactos/include/reactos/wine/config.h b/reactos/include/reactos/wine/config.h index b45073bd20c..cb26f59512c 100644 --- a/reactos/include/reactos/wine/config.h +++ b/reactos/include/reactos/wine/config.h @@ -975,12 +975,18 @@ `char[]'. */ #define YYTEXT_POINTER 1 +/* Define to a macro to output a .cfi assembly pseudo-op */ +#define __ASM_CFI(x) + /* Define to a macro to generate an assembly function directive */ #define __ASM_FUNC(name) ".def " __ASM_NAME(name) "; .scl 2; .type 32; .endef" /* Define to a macro to generate an assembly name from a C symbol */ #define __ASM_NAME(name) "_" name +/* Define to a macro to generate an stdcall suffix */ +#define __ASM_STDCALL(args) "@" #args + /* Define to empty if `const' does not conform to ANSI C. */ /* #undef const */