* Use overlapped named pipes access mode, and use GetOverlappedResult for reading/writing too.
* Add patch for waiting for server calls in RpcMgmtWaitServerListen (not fully correct one, but enough for now).
* Hacks around ntsecapi.h inclusion (it can't be used properly with winternl.h).
* Total removal of HTTP transport. Could be enabled when dynamic linking to wininet.dll will be possible.
- Change config.h to include new ASM macros. This is not platform independent.
svn path=/trunk/; revision=44130
* 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
* TODO: Handle non-i386 architectures
*/
+#include "config.h"
+#include "wine/port.h"
+
#include <stdarg.h>
#define COBJMACROS
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;
#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)
-
-#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)
+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" );
+
+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]);
+
+ return NdrClientCall2(stubless->pStubDesc, fs, args + 2);
+}
- 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));
+#define BLOCK_SIZE 1024
+#define MAX_BLOCKS 64 /* 64k methods should be enough for anybody */
- return NdrClientCall2(This->stubless->pStubDesc, fs, args);
+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];
/* 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;
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; i<count; i++) {
- struct StublessThunk *thunk = &This->thunks[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;
}
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);
}
This->pChannel = pChannel;
IRpcChannelBuffer_AddRef(pChannel);
+ if (This->base_proxy) IRpcProxyBuffer_Connect( This->base_proxy, pChannel );
return S_OK;
}
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;
}
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.@]
*/
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 ((*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;
- }
+ if (!pPSFactoryBuffer->lpVtbl) init_psfactory( pPSFactoryBuffer, pProxyFileList );
- 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 {
*/
HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer)
{
- return !(pPSFactoryBuffer->RefCount);
+ return pPSFactoryBuffer->RefCount != 0 ? S_FALSE : S_OK;
}
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));
#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 WINAPI 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 StdProxy_Construct(REFIID riid, LPUNKNOWN pUnkOuter, const ProxyFileInfo *ProxyInfo,
+ int Index, LPPSFACTORYBUFFER pPSFactory, LPRPCPROXYBUFFER *ppProxy,
+ LPVOID *ppvObj);
+
+HRESULT CStdStubBuffer_Construct(REFIID riid, LPUNKNOWN pUnkServer, PCInterfaceName name,
+ CInterfaceStubVtbl *vtbl, 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 */
* 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
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;
{
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;
}
} vtbl_method_t;
#include "poppack.h"
-static void fill_table(IUnknownVtbl *vtbl, void **methods, DWORD num)
+#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 )
{
- vtbl_method_t *method;
- void **entry;
- DWORD i;
+ 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;
+ 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++ = &block[j];
+ }
+ return TRUE;
+}
- method = (vtbl_method_t*)methods;
- entry = (void**)(vtbl + 1);
+BOOL fill_delegated_proxy_table(IUnknownVtbl *vtbl, DWORD num)
+{
+ const void **entry = (const void **)(vtbl + 1);
+ DWORD i, j;
- for(i = 3; i < num; i++)
+ 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++)
{
- *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++)
+ 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)
+static IUnknownVtbl *get_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;
- }
+ IUnknownVtbl *ret;
+
+ if (num_methods < 256) num_methods = 256; /* avoid frequent reallocations */
EnterCriticalSection(&delegating_vtbl_section);
- if(!current_vtbl.table || num_methods > current_vtbl.table->size)
+
+ if(!current_vtbl || num_methods > current_vtbl->size)
{
- DWORD size;
- DWORD old_protect;
- if(current_vtbl.table && current_vtbl.table->ref == 0)
+ 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");
- VirtualFree(current_vtbl.table->methods, 0, MEM_RELEASE);
- HeapFree(GetProcessHeap(), 0, current_vtbl.table);
+ HeapFree(GetProcessHeap(), 0, current_vtbl);
}
- 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);
+ current_vtbl = table;
}
- LeaveCriticalSection(&delegating_vtbl_section);
-}
-static IUnknownVtbl *get_delegating_vtbl(void)
-{
- IUnknownVtbl *ret;
-
- EnterCriticalSection(&delegating_vtbl_section);
- current_vtbl.table->ref++;
- ret = ¤t_vtbl.table->vtbl;
+ current_vtbl->ref++;
+ ret = ¤t_vtbl->vtbl;
LeaveCriticalSection(&delegating_vtbl_section);
return ret;
}
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;
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))
{
*
*/
-#include "epm_c.h"
+#include "epm.h"
#define EPM_PROTOCOL_DNET_NSP 0x04
#define EPM_PROTOCOL_OSI_TP4 0x05
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;
}
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;
}
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 */
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.
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);
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);
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 */
"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)
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;
+}
* RPCF_Asynchronous = 0x4000 - [async] MIDL attribute
* Reserved = 0x8000
*/
- unsigned long rpc_flags;
+ unsigned int rpc_flags;
unsigned short proc_num;
unsigned short stack_size;
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);
RPC_STATUS RpcServerAssoc_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
LPCSTR Endpoint, LPCWSTR NetworkOptions,
- unsigned long assoc_gid,
+ ULONG assoc_gid,
RpcAssoc **assoc_out)
{
RpcAssoc *assoc;
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");
if (status != RPC_S_OK)
return status;
+ NewConnection->assoc = assoc;
status = RPCRT4_OpenClientConnection(NewConnection);
if (status != RPC_S_OK)
{
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);
/* id of this association group */
ULONG assoc_group_id;
+ UUID http_uuid;
CRITICAL_SECTION cs;
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);
#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.@]
*
*/
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);
}
/***********************************************************************
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;
}
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++) {
*/
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;
*/
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;
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;
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);
TRACE("(%p,%p)\n", Binding, StringBinding);
ret = RpcBindingToStringBindingA(Binding, &str);
*StringBinding = RPCRT4_strdupAtoW((char*)str);
- RpcStringFreeA((unsigned char**)&str);
+ RpcStringFreeA(&str);
return ret;
}
*/
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 );
RPC_BINDING_HANDLE* DestinationBinding)
{
RpcBinding *DestBinding;
- RpcBinding *SrcBinding = (RpcBinding*)SourceBinding;
+ RpcBinding *SrcBinding = SourceBinding;
RPC_STATUS status;
TRACE("(%p, %p)\n", SourceBinding, DestinationBinding);
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;
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;
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)
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);
}
#include "rpcndr.h"
#include "security.h"
#include "wine/list.h"
+#include "rpc_defs.h"
typedef struct _RpcAuthInfo
TimeStamp exp;
ULONG attr;
RpcAuthInfo *AuthInfo;
+ ULONG auth_context_id;
ULONG encryption_auth_len;
ULONG signature_auth_len;
RpcQualityOfService *QOS;
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. */
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 */
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;
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;
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
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 */
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;
} 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
{
RpcPktBindHdr bind;
RpcPktBindAckHdr bind_ack;
RpcPktBindNAckHdr bind_nack;
+ RpcPktHttpHdr http;
} RpcPktHdr;
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) \
#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
#include "wine/exception.h"
#include "rpc_binding.h"
-#include "epm_c.h"
+#include "epm.h"
#include "epm_towers.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
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;
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;
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
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;
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; i<BindingVector->Count; 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; i<UuidVector->Count; 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;
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,
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));
}
}
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;
TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector);
TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
for (i=0; i<BindingVector->Count; 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; i<UuidVector->Count; 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));
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,
*/
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;
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;
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;
}
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;
/* 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)
{
return header;
}
-RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation,
- unsigned long BufferLength)
+RpcPktHdr *RPCRT4_BuildResponseHeader(ULONG DataRepresentation, ULONG BufferLength)
{
RpcPktHdr *header;
return header;
}
-RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation,
- RPC_STATUS Status)
+RpcPktHdr *RPCRT4_BuildFaultHeader(ULONG DataRepresentation, RPC_STATUS Status)
{
RpcPktHdr *header;
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)
{
return header;
}
-static RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation)
+static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation)
{
RpcPktHdr *header;
return header;
}
-RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation,
+RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation,
unsigned char RpcVersion,
unsigned char RpcVersionMinor)
{
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;
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);
}
}
+/* 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,
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);
}
/* validates version and frag_len fields */
-static RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr)
+RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr)
{
DWORD hdr_length;
}
/***********************************************************************
- * 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;
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)
*
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;
}
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;
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);
*/
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;
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);
*/
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);
*/
RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
{
- RpcBinding* bind = (RpcBinding*)pMsg->Handle;
+ RpcBinding* bind = pMsg->Handle;
RpcConnection* conn;
RPC_STATUS status;
RpcPktHdr *hdr;
*/
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;
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;
*/
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);
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);
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;
/* 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;
}
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;
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) {
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);
}
*
* 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);
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;
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;
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);
}
/***********************************************************************
{
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;
*/
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);
}
/***********************************************************************
*/
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);
}
/***********************************************************************
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;
*/
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;
* 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
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 */
# ifndef EAGAIN
# define EAGAIN WSAEWOULDBLOCK
# endif
+# undef errno
+# define errno WSAGetLastError()
#else
# include <errno.h>
# ifdef HAVE_UNISTD_H
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# endif
+# ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+# endif
+# ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+# endif
# define closesocket close
+# define ioctlsocket ioctl
#endif /* defined(__MINGW32__) || defined (_MSC_VER) */
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winerror.h"
+#include "wininet.h"
#include "winternl.h"
#include "wine/unicode.h"
#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);
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);
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);
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;
}
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;
}
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;
}
/**** ncacn_ip_tcp support ****/
-#ifdef HAVE_SOCKETPAIR
+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;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ int ret;
+ size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
+
+ TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
+
+ if (!tower_data)
+ return size;
+
+ tcp_floor = (twr_tcp_floor_t *)tower_data;
+ tower_data += sizeof(*tcp_floor);
+
+ ipv4_floor = (twr_ipv4_floor_t *)tower_data;
+
+ tcp_floor->count_lhs = sizeof(tcp_floor->protid);
+ 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;
+ ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
+
+ hints.ai_flags = AI_NUMERICHOST;
+ /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
+ hints.ai_family = PF_INET;
+ 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(networkaddr, endpoint, &hints, &ai);
+ if (ret)
+ {
+ ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
+ if (ret)
+ {
+ ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
+ return 0;
+ }
+ }
+
+ if (ai->ai_family == PF_INET)
+ {
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
+ tcp_floor->port = sin->sin_port;
+ ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
+ }
+ else
+ {
+ ERR("unexpected protocol family %d\n", ai->ai_family);
+ return 0;
+ }
+
+ freeaddrinfo(ai);
+
+ return size;
+}
+
+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;
+ struct in_addr in_addr;
+
+ TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
+
+ if (tower_size < sizeof(*tcp_floor))
+ return EPT_S_NOT_REGISTERED;
+
+ tower_data += sizeof(*tcp_floor);
+ tower_size -= sizeof(*tcp_floor);
+
+ if (tower_size < sizeof(*ipv4_floor))
+ return EPT_S_NOT_REGISTERED;
+
+ ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
+
+ if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
+ (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) ||
+ (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
+ return EPT_S_NOT_REGISTERED;
+
+ if (endpoint)
+ {
+ *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
+ if (!*endpoint)
+ return RPC_S_OUT_OF_RESOURCES;
+ sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
+ }
+
+ if (networkaddr)
+ {
+ *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
+ if (!*networkaddr)
+ {
+ if (endpoint)
+ {
+ I_RpcFree(*endpoint);
+ *endpoint = NULL;
+ }
+ return RPC_S_OUT_OF_RESOURCES;
+ }
+ in_addr.s_addr = ipv4_floor->ipv4addr;
+ if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
+ {
+ ERR("inet_ntop: %s\n", strerror(errno));
+ I_RpcFree(*networkaddr);
+ *networkaddr = NULL;
+ if (endpoint)
+ {
+ I_RpcFree(*endpoint);
+ *endpoint = NULL;
+ }
+ return EPT_S_NOT_REGISTERED;
+ }
+ }
+
+ 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;
if (tcpc == NULL)
return NULL;
tcpc->sock = -1;
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
+ if (!rpcrt4_sock_wait_init(tcpc))
{
- ERR("socketpair() failed: %s\n", strerror(errno));
HeapFree(GetProcessHeap(), 0, tcpc);
return NULL;
}
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))
{
/* 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 */
+ setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+ nonblocking = 1;
+ ioctlsocket(sock, FIONBIO, &nonblocking);
tcpc->sock = sock;
return RPC_S_SERVER_UNAVAILABLE;
}
-static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
+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;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
- ret = getaddrinfo(NULL, endpoint, &hints, &ai);
+ ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
if (ret)
{
ERR("getaddrinfo for port %s failed: %s\n", endpoint,
{
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];
- char service[256];
getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
host, sizeof(host), service, sizeof(service),
NI_NUMERICHOST | NI_NUMERICSERV);
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,
- endpoint, NULL, NULL, NULL);
+ service, NULL, NULL, NULL);
if (create_status != RPC_S_OK)
{
closesocket(sock);
* race-condition (poll() says it is readable, connection drops,
* and accept() blocks until the next connection comes...)
*/
- ret = fcntl(sock, F_SETFL, O_NONBLOCK);
+ nonblocking = 1;
+ ret = ioctlsocket(sock, FIONBIO, &nonblocking);
if (ret < 0)
{
WARN("couldn't make socket non-blocking, error %d\n", ret);
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);
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);
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);
+ nonblocking = 1;
+ ioctlsocket(ret, FIONBIO, &nonblocking);
client->sock = ret;
TRACE("Accepted a new TCP connection\n");
return RPC_S_OK;
}
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));
+ 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 -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));
+ 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);
if (tcpc->sock != -1)
closesocket(tcpc->sock);
tcpc->sock = -1;
- close(tcpc->cancel_fds[0]);
- close(tcpc->cancel_fds[1]);
+ rpcrt4_sock_wait_destroy(tcpc);
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);
+ rpcrt4_sock_wait_cancel(tcpc);
}
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;
- }
-
+ if (!rpcrt4_sock_wait_for_recv(tcpc))
+ return -1;
return 0;
}
const char *networkaddr,
const char *endpoint)
{
- twr_tcp_floor_t *tcp_floor;
- twr_ipv4_floor_t *ipv4_floor;
- struct addrinfo *ai;
- struct addrinfo hints;
- int ret;
- size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
+ return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
+ EPM_PROTOCOL_TCP, endpoint);
+}
- TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
-
- if (!tower_data)
- return size;
-
- tcp_floor = (twr_tcp_floor_t *)tower_data;
- tower_data += sizeof(*tcp_floor);
-
- ipv4_floor = (twr_ipv4_floor_t *)tower_data;
-
- tcp_floor->count_lhs = sizeof(tcp_floor->protid);
- tcp_floor->protid = EPM_PROTOCOL_TCP;
- tcp_floor->count_rhs = sizeof(tcp_floor->port);
-
- ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
- ipv4_floor->protid = EPM_PROTOCOL_IP;
- ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
-
- hints.ai_flags = AI_NUMERICHOST;
- /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
- hints.ai_family = PF_INET;
- 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(networkaddr, endpoint, &hints, &ai);
- if (ret)
- {
- ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
- if (ret)
- {
- ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
- return 0;
- }
- }
-
- if (ai->ai_family == PF_INET)
- {
- const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
- tcp_floor->port = sin->sin_port;
- ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
- }
- else
- {
- ERR("unexpected protocol family %d\n", ai->ai_family);
- return 0;
- }
-
- freeaddrinfo(ai);
-
- 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)
-{
- const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
- const twr_ipv4_floor_t *ipv4_floor;
- struct in_addr in_addr;
-
- TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
-
- if (tower_size < sizeof(*tcp_floor))
- return EPT_S_NOT_REGISTERED;
-
- tower_data += sizeof(*tcp_floor);
- tower_size -= sizeof(*tcp_floor);
-
- if (tower_size < sizeof(*ipv4_floor))
- return EPT_S_NOT_REGISTERED;
-
- 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->count_rhs != sizeof(tcp_floor->port)) ||
- (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
- (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
- (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
- return EPT_S_NOT_REGISTERED;
-
- if (endpoint)
- {
- *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
- if (!*endpoint)
- return RPC_S_OUT_OF_RESOURCES;
- sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
- }
-
- if (networkaddr)
- {
- *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
- if (!*networkaddr)
- {
- if (endpoint)
- {
- I_RpcFree(*endpoint);
- *endpoint = NULL;
- }
- return RPC_S_OUT_OF_RESOURCES;
- }
- in_addr.s_addr = ipv4_floor->ipv4addr;
- if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
- {
- ERR("inet_ntop: %s\n", strerror(errno));
- I_RpcFree(*networkaddr);
- *networkaddr = NULL;
- if (endpoint)
- {
- I_RpcFree(*endpoint);
- *endpoint = NULL;
- }
- return EPT_S_NOT_REGISTERED;
- }
- }
-
- return RPC_S_OK;
-}
+#ifdef HAVE_SOCKETPAIR
typedef struct _RpcServerProtseq_sock
{
return 1;
}
-#endif /* HAVE_SOCKETPAIR */
+#else /* HAVE_SOCKETPAIR */
-static const struct connection_ops conn_protseq_list[] = {
- { "ncacn_np",
- { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
- rpcrt4_conn_np_alloc,
- rpcrt4_ncacn_np_open,
- rpcrt4_ncacn_np_handoff,
- rpcrt4_conn_np_read,
- rpcrt4_conn_np_write,
- rpcrt4_conn_np_close,
- rpcrt4_conn_np_cancel_call,
- rpcrt4_conn_np_wait_for_incoming_data,
- rpcrt4_ncacn_np_get_top_of_tower,
- rpcrt4_ncacn_np_parse_top_of_tower,
- },
- { "ncalrpc",
- { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
- rpcrt4_conn_np_alloc,
- rpcrt4_ncalrpc_open,
- rpcrt4_ncalrpc_handoff,
- rpcrt4_conn_np_read,
- rpcrt4_conn_np_write,
- rpcrt4_conn_np_close,
- rpcrt4_conn_np_cancel_call,
- rpcrt4_conn_np_wait_for_incoming_data,
- rpcrt4_ncalrpc_get_top_of_tower,
- rpcrt4_ncalrpc_parse_top_of_tower,
- },
-#ifdef HAVE_SOCKETPAIR
- { "ncacn_ip_tcp",
- { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
- rpcrt4_conn_tcp_alloc,
- rpcrt4_ncacn_ip_tcp_open,
- rpcrt4_conn_tcp_handoff,
- rpcrt4_conn_tcp_read,
- rpcrt4_conn_tcp_write,
- rpcrt4_conn_tcp_close,
- rpcrt4_conn_tcp_cancel_call,
- rpcrt4_conn_tcp_wait_for_incoming_data,
- rpcrt4_ncacn_ip_tcp_get_top_of_tower,
- rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
- }
-#endif
-};
+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 const struct protseq_ops protseq_list[] =
+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)
{
- "ncacn_np",
- rpcrt4_protseq_np_alloc,
- rpcrt4_protseq_np_signal_state_changed,
- rpcrt4_protseq_np_get_wait_array,
- rpcrt4_protseq_np_free_wait_array,
- rpcrt4_protseq_np_wait_for_new_connection,
- rpcrt4_protseq_ncacn_np_open_endpoint,
- },
+ 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)
{
- "ncalrpc",
- rpcrt4_protseq_np_alloc,
- rpcrt4_protseq_np_signal_state_changed,
- rpcrt4_protseq_np_get_wait_array,
- rpcrt4_protseq_np_free_wait_array,
- rpcrt4_protseq_np_wait_for_new_connection,
- rpcrt4_protseq_ncalrpc_open_endpoint,
- },
-#ifdef HAVE_SOCKETPAIR
+ 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)
{
- "ncacn_ip_tcp",
- rpcrt4_protseq_sock_alloc,
- rpcrt4_protseq_sock_signal_state_changed,
- rpcrt4_protseq_sock_get_wait_array,
- rpcrt4_protseq_sock_free_wait_array,
- rpcrt4_protseq_sock_wait_for_new_connection,
- rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
- },
-#endif
+ 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) : "<status text unavailable>");
+ 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 },
+ rpcrt4_conn_np_alloc,
+ rpcrt4_ncacn_np_open,
+ rpcrt4_ncacn_np_handoff,
+ rpcrt4_conn_np_read,
+ rpcrt4_conn_np_write,
+ rpcrt4_conn_np_close,
+ rpcrt4_conn_np_cancel_call,
+ 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 },
+ rpcrt4_conn_np_alloc,
+ rpcrt4_ncalrpc_open,
+ rpcrt4_ncalrpc_handoff,
+ rpcrt4_conn_np_read,
+ rpcrt4_conn_np_write,
+ rpcrt4_conn_np_close,
+ rpcrt4_conn_np_cancel_call,
+ rpcrt4_conn_np_wait_for_incoming_data,
+ rpcrt4_ncalrpc_get_top_of_tower,
+ rpcrt4_ncalrpc_parse_top_of_tower,
+ NULL,
+ },
+ { "ncacn_ip_tcp",
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
+ rpcrt4_conn_tcp_alloc,
+ rpcrt4_ncacn_ip_tcp_open,
+ rpcrt4_conn_tcp_handoff,
+ rpcrt4_conn_tcp_read,
+ rpcrt4_conn_tcp_write,
+ rpcrt4_conn_tcp_close,
+ rpcrt4_conn_tcp_cancel_call,
+ 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
+};
+
+
+static const struct protseq_ops protseq_list[] =
+{
+ {
+ "ncacn_np",
+ rpcrt4_protseq_np_alloc,
+ rpcrt4_protseq_np_signal_state_changed,
+ rpcrt4_protseq_np_get_wait_array,
+ rpcrt4_protseq_np_free_wait_array,
+ rpcrt4_protseq_np_wait_for_new_connection,
+ rpcrt4_protseq_ncacn_np_open_endpoint,
+ },
+ {
+ "ncalrpc",
+ rpcrt4_protseq_np_alloc,
+ rpcrt4_protseq_np_signal_state_changed,
+ rpcrt4_protseq_np_get_wait_array,
+ rpcrt4_protseq_np_free_wait_array,
+ rpcrt4_protseq_np_wait_for_new_connection,
+ rpcrt4_protseq_ncalrpc_open_endpoint,
+ },
+ {
+ "ncacn_ip_tcp",
+ rpcrt4_protseq_sock_alloc,
+ rpcrt4_protseq_sock_signal_state_changed,
+ rpcrt4_protseq_sock_get_wait_array,
+ rpcrt4_protseq_sock_free_wait_array,
+ rpcrt4_protseq_sock_wait_for_new_connection,
+ rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
+ },
};
#define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS)
{
+ static LONG next_id;
const struct connection_ops *ops;
RpcConnection* NewConnection;
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);
<library>user32</library>
<library>advapi32</library>
<library>secur32</library>
+ <!--library>wininet</library-->
<library>iphlpapi</library>
<library>ws2_32</library>
<library>ntdll</library>
@ 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)
@ 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
#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"
#include "rpcproxy.h"
#include "rpc_binding.h"
+#include "rpc_server.h"
#include "wine/debug.h"
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 =
{
break;
case DLL_PROCESS_DETACH:
+ RPCRT4_destroy_all_protseqs();
break;
}
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.@]
*
* 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;
}
/*************************************************************************
`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 */