diff --git a/reactos/dll/win32/rpcrt4/cproxy.c b/reactos/dll/win32/rpcrt4/cproxy.c index f045e0c8e33..f0996d00d90 100644 --- a/reactos/dll/win32/rpcrt4/cproxy.c +++ b/reactos/dll/win32/rpcrt4/cproxy.c @@ -15,10 +15,9 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: Handle non-i386 architectures - * Get rid of #if 0'ed code. */ #include @@ -45,7 +44,7 @@ struct StublessThunk; typedef struct { const IRpcProxyBufferVtbl *lpVtbl; LPVOID *PVtbl; - DWORD RefCount; + LONG RefCount; const MIDL_STUBLESS_PROXY_INFO *stubless; const IID* piid; LPUNKNOWN pUnkOuter; @@ -102,7 +101,7 @@ static HRESULT WINAPI ObjectStubless(DWORD index) PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index]; unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; - TRACE("(%p)->(%ld)([%d bytes]) ret=%08lx\n", iface, index, bytes, *(DWORD*)(args+bytes)); + TRACE("(%p)->(%d)([%d bytes]) ret=%08x\n", iface, index, bytes, *(DWORD*)(args+bytes)); return NdrClientCall2(This->stubless->pStubDesc, fs, args); } @@ -223,13 +222,13 @@ static HRESULT WINAPI StdProxy_QueryInterface(LPRPCPROXYBUFFER iface, if (IsEqualGUID(&IID_IUnknown,riid) || IsEqualGUID(This->piid,riid)) { *obj = &This->PVtbl; - This->RefCount++; + InterlockedIncrement(&This->RefCount); return S_OK; } if (IsEqualGUID(&IID_IRpcProxyBuffer,riid)) { *obj = &This->lpVtbl; - This->RefCount++; + InterlockedIncrement(&This->RefCount); return S_OK; } @@ -241,19 +240,19 @@ static ULONG WINAPI StdProxy_AddRef(LPRPCPROXYBUFFER iface) ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); TRACE("(%p)->AddRef()\n",This); - return ++(This->RefCount); + return InterlockedIncrement(&This->RefCount); } static ULONG WINAPI StdProxy_Release(LPRPCPROXYBUFFER iface) { + ULONG refs; ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); TRACE("(%p)->Release()\n",This); - if (!--(This->RefCount)) { + refs = InterlockedDecrement(&This->RefCount); + if (!refs) StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); - return 0; - } - return This->RefCount; + return refs; } static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, @@ -285,24 +284,22 @@ static const IRpcProxyBufferVtbl StdProxy_Vtbl = StdProxy_Disconnect }; -HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, - LPRPCCHANNELBUFFER *ppChannel) +static void StdProxy_GetChannel(LPVOID iface, + LPRPCCHANNELBUFFER *ppChannel) { ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); TRACE("(%p)->GetChannel(%p) %s\n",This,ppChannel,This->name); *ppChannel = This->pChannel; - return S_OK; } -HRESULT WINAPI StdProxy_GetIID(LPVOID iface, - const IID **ppiid) +static void StdProxy_GetIID(LPVOID iface, + const IID **ppiid) { ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); TRACE("(%p)->GetIID(%p) %s\n",This,ppiid,This->name); *ppiid = This->piid; - return S_OK; } HRESULT WINAPI IUnknown_QueryInterface_Proxy(LPUNKNOWN iface, @@ -318,32 +315,136 @@ ULONG WINAPI IUnknown_AddRef_Proxy(LPUNKNOWN iface) { ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); TRACE("(%p)->AddRef() %s\n",This,This->name); -#if 0 /* interface refcounting */ - return ++(This->RefCount); -#else /* object refcounting */ return IUnknown_AddRef(This->pUnkOuter); -#endif } ULONG WINAPI IUnknown_Release_Proxy(LPUNKNOWN iface) { ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); TRACE("(%p)->Release() %s\n",This,This->name); -#if 0 /* interface refcounting */ - if (!--(This->RefCount)) { - StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); - return 0; - } - return This->RefCount; -#else /* object refcounting */ return IUnknown_Release(This->pUnkOuter); -#endif +} + +/*********************************************************************** + * NdrProxyInitialize [RPCRT4.@] + */ +void WINAPI NdrProxyInitialize(void *This, + PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + unsigned int ProcNum) +{ + TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer); + IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer, + &pStubMsg->dwDestContext, + &pStubMsg->pvDestContext); + TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer); +} + +/*********************************************************************** + * NdrProxyGetBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyGetBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + const IID *riid = NULL; + + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + pStubMsg->dwStubPhase = PROXY_GETBUFFER; + StdProxy_GetIID(This, &riid); + hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + riid); + if (FAILED(hr)) + { + RpcRaiseException(hr); + return; + } + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + pStubMsg->dwStubPhase = PROXY_MARSHAL; +} + +/*********************************************************************** + * NdrProxySendReceive [RPCRT4.@] + */ +void WINAPI NdrProxySendReceive(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + ULONG Status = 0; + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + + if (!pStubMsg->pRpcChannelBuffer) + { + WARN("Trying to use disconnected proxy %p\n", This); + RpcRaiseException(RPC_E_DISCONNECTED); + } + + pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; + hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + &Status); + pStubMsg->dwStubPhase = PROXY_UNMARSHAL; + pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + + /* raise exception if call failed */ + if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); + else if (FAILED(hr)) RpcRaiseException(hr); +} + +/*********************************************************************** + * NdrProxyFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyFreeBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + hr = IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg); +} + +/*********************************************************************** + * NdrProxyErrorHandler [RPCRT4.@] + */ +HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode) +{ + WARN("(0x%08x): a proxy call failed\n", dwExceptionCode); + + if (FAILED(dwExceptionCode)) + return dwExceptionCode; + else + return HRESULT_FROM_WIN32(dwExceptionCode); } HRESULT WINAPI CreateProxyFromTypeInfo( LPTYPEINFO pTypeInfo, LPUNKNOWN pUnkOuter, REFIID riid, LPRPCPROXYBUFFER *ppProxy, LPVOID *ppv ) { + typedef INT (WINAPI *MessageBoxA)(HWND,LPCSTR,LPCSTR,UINT); + HMODULE hUser32 = LoadLibraryA("user32"); + MessageBoxA pMessageBoxA = GetProcAddress(hUser32, "MessageBoxA"); + FIXME("%p %p %s %p %p\n", pTypeInfo, pUnkOuter, debugstr_guid(riid), ppProxy, ppv); + if (pMessageBoxA) + { + pMessageBoxA(NULL, + "The native implementation of OLEAUT32.DLL cannot be used " + "with Wine's RPCRT4.DLL. Remove OLEAUT32.DLL and try again.\n", + "Wine: Unimplemented CreateProxyFromTypeInfo", + 0x10); + ExitProcess(1); + } return E_NOTIMPL; } diff --git a/reactos/dll/win32/rpcrt4/cpsf.c b/reactos/dll/win32/rpcrt4/cpsf.c index 44bb5a99255..dcf37219195 100644 --- a/reactos/dll/win32/rpcrt4/cpsf.c +++ b/reactos/dll/win32/rpcrt4/cpsf.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -110,6 +110,12 @@ static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, pUnkServer,ppStub); if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) return E_NOINTERFACE; + + if(ProxyInfo->pDelegatedIIDs && ProxyInfo->pDelegatedIIDs[Index]) + return CStdStubBuffer_Delegating_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], + ProxyInfo->pStubVtblList[Index], ProxyInfo->pDelegatedIIDs[Index], + iface, ppStub); + return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], ProxyInfo->pStubVtblList[Index], iface, ppStub); } @@ -138,6 +144,7 @@ HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, *ppv = NULL; if (!pPSFactoryBuffer->lpVtbl) { const ProxyFileInfo **pProxyFileList2; + int max_delegating_vtbl_size = 0; pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; pPSFactoryBuffer->RefCount = 0; pPSFactoryBuffer->pProxyFileList = pProxyFileList; @@ -150,11 +157,19 @@ HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, void **pRpcStubVtbl = (void **)&(*pProxyFileList2)->pStubVtblList[i]->Vtbl; 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; + } + 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 (IsEqualGUID(rclsid, pclsid)) return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); @@ -210,7 +225,7 @@ HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { if (name) - RegSetValueExA(key, NULL, 0, REG_SZ, (LPBYTE)name, strlen(name)); + RegSetValueExA(key, NULL, 0, REG_SZ, (const BYTE *)name, strlen(name)); if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0, KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { snprintf(module, sizeof(module), "{%s}", clsid); @@ -230,9 +245,11 @@ HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, TRACE("registering CLSID %s => %s\n", clsid, module); if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + RegSetValueExA(subkey, NULL, 0, REG_SZ, (const BYTE *)"PSFactoryBuffer", strlen("PSFactoryBuffer")); if (RegCreateKeyExA(key, "InProcServer32", 0, NULL, 0, KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { RegSetValueExA(subkey, NULL, 0, REG_SZ, (LPBYTE)module, strlen(module)); + RegSetValueExA(subkey, "ThreadingModel", 0, REG_SZ, (const BYTE *)"Both", strlen("Both")); RegCloseKey(subkey); } RegCloseKey(key); diff --git a/reactos/dll/win32/rpcrt4/cpsf.h b/reactos/dll/win32/rpcrt4/cpsf.h index cf1572b9ac6..5ce8fe6575e 100644 --- a/reactos/dll/win32/rpcrt4/cpsf.h +++ b/reactos/dll/win32/rpcrt4/cpsf.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_CPSF_H @@ -28,10 +28,6 @@ HRESULT WINAPI StdProxy_Construct(REFIID riid, LPPSFACTORYBUFFER pPSFactory, LPRPCPROXYBUFFER *ppProxy, LPVOID *ppvObj); -HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, - LPRPCCHANNELBUFFER *ppChannel); -HRESULT WINAPI StdProxy_GetIID(LPVOID iface, - const IID **piid); HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, LPUNKNOWN pUnkServer, @@ -40,8 +36,21 @@ HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, LPPSFACTORYBUFFER pPSFactory, LPRPCSTUBBUFFER *ppStub); +HRESULT WINAPI 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); + +HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub); #endif /* __WINE_CPSF_H */ diff --git a/reactos/dll/win32/rpcrt4/cstub.c b/reactos/dll/win32/rpcrt4/cstub.c index 41c09437c3f..0ae85ae055f 100644 --- a/reactos/dll/win32/rpcrt4/cstub.c +++ b/reactos/dll/win32/rpcrt4/cstub.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -25,18 +25,38 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "excpt.h" #include "objbase.h" - #include "rpcproxy.h" #include "wine/debug.h" +#include "wine/exception.h" #include "cpsf.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); -#define STUB_HEADER(This) (((CInterfaceStubHeader*)((This)->lpVtbl))[-1]) +#define STUB_HEADER(This) (((const CInterfaceStubHeader*)((This)->lpVtbl))[-1]) + +static WINE_EXCEPTION_FILTER(stub_filter) +{ + if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_EXECUTE_HANDLER; +} + +typedef struct +{ + IUnknownVtbl *base_obj; + IRpcStubBuffer *base_stub; + CStdStubBuffer stub_buffer; +} cstdstubbuffer_delegating_t; + +static inline cstdstubbuffer_delegating_t *impl_from_delegating( IRpcStubBuffer *iface ) +{ + return (cstdstubbuffer_delegating_t*)((char *)iface - FIELD_OFFSET(cstdstubbuffer_delegating_t, stub_buffer)); +} HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, LPUNKNOWN pUnkServer, @@ -46,7 +66,8 @@ HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, LPRPCSTUBBUFFER *ppStub) { CStdStubBuffer *This; - + IUnknown *pvServer; + HRESULT r; TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); TRACE("vtbl=%p\n", &vtbl->Vtbl); @@ -56,20 +77,233 @@ HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, return RPC_E_UNEXPECTED; } + r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer); + if(FAILED(r)) + return r; + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CStdStubBuffer)); - if (!This) return E_OUTOFMEMORY; + if (!This) { + IUnknown_Release(pvServer); + return E_OUTOFMEMORY; + } This->lpVtbl = &vtbl->Vtbl; This->RefCount = 1; - This->pvServerObject = pUnkServer; + This->pvServerObject = pvServer; This->pPSFactory = pPSFactory; *ppStub = (LPRPCSTUBBUFFER)This; - IUnknown_AddRef(This->pvServerObject); IPSFactoryBuffer_AddRef(pPSFactory); return S_OK; } +static CRITICAL_SECTION delegating_vtbl_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &delegating_vtbl_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": delegating_vtbl_section") } +}; +static CRITICAL_SECTION delegating_vtbl_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + +typedef struct +{ + DWORD ref; + IUnknownVtbl vtbl; +} ref_counted_vtbl; + +static struct +{ + ref_counted_vtbl *table; + DWORD size; +} current_vtbl; + + +static HRESULT WINAPI delegating_QueryInterface(IUnknown *pUnk, REFIID iid, void **ppv) +{ + *ppv = (void *)pUnk; + return S_OK; +} + +static ULONG WINAPI delegating_AddRef(IUnknown *pUnk) +{ + return 1; +} + +static ULONG WINAPI delegating_Release(IUnknown *pUnk) +{ + return 1; +} + +#if defined(__i386__) + +/* The idea here is to replace the first param on the stack + ie. This (which will point to cstdstubbuffer_delegating_t) + with This->stub_buffer.pvServerObject and then jump to the + relevant offset in This->stub_buffer.pvServerObject's vtbl. +*/ +#include "pshpack1.h" +typedef struct { + DWORD mov1; /* mov 0x4(%esp), %eax 8b 44 24 04 */ + WORD mov2; /* mov 0x10(%eax), %eax 8b 40 */ + BYTE sixteen; /* 10 */ + DWORD mov3; /* mov %eax, 0x4(%esp) 89 44 24 04 */ + WORD mov4; /* mov (%eax), %eax 8b 00 */ + WORD mov5; /* mov offset(%eax), %eax 8b 80 */ + DWORD offset; /* xx xx xx xx */ + WORD jmp; /* jmp *%eax ff e0 */ + BYTE pad[3]; /* lea 0x0(%esi), %esi 8d 76 00 */ +} vtbl_method_t; +#include "poppack.h" + +static void fill_table(IUnknownVtbl *vtbl, DWORD num) +{ + vtbl_method_t *method; + void **entry; + DWORD i; + + vtbl->QueryInterface = delegating_QueryInterface; + vtbl->AddRef = delegating_AddRef; + vtbl->Release = delegating_Release; + + method = (vtbl_method_t*)((void **)vtbl + num); + entry = (void**)(vtbl + 1); + + for(i = 3; i < num; 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++; + } +} + +#else /* __i386__ */ + +typedef struct {int dummy;} vtbl_method_t; +static void fill_table(IUnknownVtbl *vtbl, DWORD num) +{ + ERR("delegated stubs are not supported on this architecture\n"); +} + +#endif /* __i386__ */ + +void create_delegating_vtbl(DWORD num_methods) +{ + TRACE("%d\n", num_methods); + if(num_methods <= 3) + { + ERR("should have more than %d methods\n", num_methods); + return; + } + + EnterCriticalSection(&delegating_vtbl_section); + if(num_methods > current_vtbl.size) + { + DWORD size; + if(current_vtbl.table && current_vtbl.table->ref == 0) + { + TRACE("freeing old table\n"); + HeapFree(GetProcessHeap(), 0, current_vtbl.table); + } + size = sizeof(DWORD) + num_methods * sizeof(void*) + (num_methods - 3) * sizeof(vtbl_method_t); + current_vtbl.table = HeapAlloc(GetProcessHeap(), 0, size); + fill_table(¤t_vtbl.table->vtbl, num_methods); + current_vtbl.table->ref = 0; + current_vtbl.size = num_methods; + } + 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; + LeaveCriticalSection(&delegating_vtbl_section); + return ret; +} + +static void release_delegating_vtbl(IUnknownVtbl *vtbl) +{ + ref_counted_vtbl *table = (ref_counted_vtbl*)((DWORD *)vtbl - 1); + + EnterCriticalSection(&delegating_vtbl_section); + table->ref--; + TRACE("ref now %d\n", table->ref); + if(table->ref == 0 && table != current_vtbl.table) + { + TRACE("... and we're not current so free'ing\n"); + 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) +{ + cstdstubbuffer_delegating_t *This; + IUnknown *pvServer; + HRESULT r; + + TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); + TRACE("iid=%s delegating to %s\n", debugstr_guid(vtbl->header.piid), debugstr_guid(delegating_iid)); + TRACE("vtbl=%p\n", &vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) + { + ERR("IID mismatch during stub creation\n"); + return RPC_E_UNEXPECTED; + } + + r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer); + if(FAILED(r)) return r; + + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); + if (!This) + { + IUnknown_Release(pvServer); + return E_OUTOFMEMORY; + } + + This->base_obj = get_delegating_vtbl(); + r = create_stub(delegating_iid, (IUnknown*)&This->base_obj, &This->base_stub); + if(FAILED(r)) + { + release_delegating_vtbl(This->base_obj); + HeapFree(GetProcessHeap(), 0, This); + IUnknown_Release(pvServer); + return r; + } + + This->stub_buffer.lpVtbl = &vtbl->Vtbl; + This->stub_buffer.RefCount = 1; + This->stub_buffer.pvServerObject = pvServer; + This->stub_buffer.pPSFactory = pPSFactory; + *ppStub = (LPRPCSTUBBUFFER)&This->stub_buffer; + + IPSFactoryBuffer_AddRef(pPSFactory); + return S_OK; +} + HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *obj) @@ -77,12 +311,14 @@ HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, CStdStubBuffer *This = (CStdStubBuffer *)iface; TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IRpcStubBuffer,riid)) { - *obj = This; - This->RefCount++; + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IRpcStubBuffer, riid)) + { + IUnknown_AddRef(iface); + *obj = iface; return S_OK; } + *obj = NULL; return E_NOINTERFACE; } @@ -90,50 +326,81 @@ ULONG WINAPI CStdStubBuffer_AddRef(LPRPCSTUBBUFFER iface) { CStdStubBuffer *This = (CStdStubBuffer *)iface; TRACE("(%p)->AddRef()\n",This); - return ++(This->RefCount); + return InterlockedIncrement(&This->RefCount); } ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface, LPPSFACTORYBUFFER pPSF) { CStdStubBuffer *This = (CStdStubBuffer *)iface; + ULONG refs; + TRACE("(%p)->Release()\n",This); - if (!--(This->RefCount)) { + refs = InterlockedDecrement(&This->RefCount); + if (!refs) + { + /* test_Release shows that native doesn't call Disconnect here. + We'll leave it in for the time being. */ IRpcStubBuffer_Disconnect(iface); - if(This->pPSFactory) - IPSFactoryBuffer_Release(This->pPSFactory); + + IPSFactoryBuffer_Release(pPSF); HeapFree(GetProcessHeap(),0,This); - return 0; } - return This->RefCount; + return refs; } ULONG WINAPI NdrCStdStubBuffer2_Release(LPRPCSTUBBUFFER iface, LPPSFACTORYBUFFER pPSF) { - FIXME("Not implemented\n"); - return 0; + cstdstubbuffer_delegating_t *This = impl_from_delegating( iface ); + ULONG refs; + + TRACE("(%p)->Release()\n", This); + + refs = InterlockedDecrement(&This->stub_buffer.RefCount); + if (!refs) + { + /* Just like NdrCStdStubBuffer_Release, we shouldn't call + Disconnect here */ + IRpcStubBuffer_Disconnect((IRpcStubBuffer *)&This->stub_buffer); + + IRpcStubBuffer_Release(This->base_stub); + release_delegating_vtbl(This->base_obj); + + IPSFactoryBuffer_Release(pPSF); + HeapFree(GetProcessHeap(), 0, This); + } + + return refs; } HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN lpUnkServer) { - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); - This->pvServerObject = lpUnkServer; - return S_OK; + CStdStubBuffer *This = (CStdStubBuffer *)iface; + HRESULT r; + IUnknown *new = NULL; + + TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); + + r = IUnknown_QueryInterface(lpUnkServer, STUB_HEADER(This).piid, (void**)&new); + new = InterlockedExchangePointer((void**)&This->pvServerObject, new); + if(new) + IUnknown_Release(new); + return r; } void WINAPI CStdStubBuffer_Disconnect(LPRPCSTUBBUFFER iface) { - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->Disconnect()\n",This); - if (This->pvServerObject) - { - IUnknown_Release(This->pvServerObject); - This->pvServerObject = NULL; - } + CStdStubBuffer *This = (CStdStubBuffer *)iface; + IUnknown *old; + TRACE("(%p)->Disconnect()\n",This); + + old = InterlockedExchangePointer((void**)&This->pvServerObject, NULL); + + if(old) + IUnknown_Release(old); } HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface, @@ -142,13 +409,29 @@ HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface, { CStdStubBuffer *This = (CStdStubBuffer *)iface; DWORD dwPhase = STUB_UNMARSHAL; + HRESULT hr = S_OK; + TRACE("(%p)->Invoke(%p,%p)\n",This,pMsg,pChannel); - if (STUB_HEADER(This).pDispatchTable) - STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); - else /* pure interpreted */ - NdrStubCall2(iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); - return S_OK; + __TRY + { + if (STUB_HEADER(This).pDispatchTable) + STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); + else /* pure interpreted */ + NdrStubCall2(iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); + } + __EXCEPT(stub_filter) + { + DWORD dwExceptionCode = GetExceptionCode(); + WARN("a stub call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode); + if (FAILED(dwExceptionCode)) + hr = dwExceptionCode; + else + hr = HRESULT_FROM_WIN32(dwExceptionCode); + } + __ENDTRY + + return hr; } LPRPCSTUBBUFFER WINAPI CStdStubBuffer_IsIIDSupported(LPRPCSTUBBUFFER iface, @@ -195,8 +478,110 @@ const IRpcStubBufferVtbl CStdStubBuffer_Vtbl = CStdStubBuffer_DebugServerRelease }; +static HRESULT WINAPI CStdStubBuffer_Delegating_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + HRESULT r; + TRACE("(%p)->Connect(%p)\n", This, lpUnkServer); + + r = CStdStubBuffer_Connect(iface, lpUnkServer); + if(SUCCEEDED(r)) + r = IRpcStubBuffer_Connect(This->base_stub, (IUnknown*)&This->base_obj); + + return r; +} + +static void WINAPI CStdStubBuffer_Delegating_Disconnect(LPRPCSTUBBUFFER iface) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + TRACE("(%p)->Disconnect()\n", This); + + IRpcStubBuffer_Disconnect(This->base_stub); + CStdStubBuffer_Disconnect(iface); +} + +static ULONG WINAPI CStdStubBuffer_Delegating_CountRefs(LPRPCSTUBBUFFER iface) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + ULONG ret; + TRACE("(%p)->CountRefs()\n", This); + + ret = CStdStubBuffer_CountRefs(iface); + ret += IRpcStubBuffer_CountRefs(This->base_stub); + + return ret; +} + +const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl = +{ + CStdStubBuffer_QueryInterface, + CStdStubBuffer_AddRef, + NULL, + CStdStubBuffer_Delegating_Connect, + CStdStubBuffer_Delegating_Disconnect, + CStdStubBuffer_Invoke, + CStdStubBuffer_IsIIDSupported, + CStdStubBuffer_Delegating_CountRefs, + CStdStubBuffer_DebugServerQueryInterface, + CStdStubBuffer_DebugServerRelease +}; + const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface) { CStdStubBuffer *This = (CStdStubBuffer *)iface; return STUB_HEADER(This).pServerInfo; } + +/************************************************************************ + * NdrStubForwardingFunction [RPCRT4.@] + */ +void __RPC_STUB NdrStubForwardingFunction( IRpcStubBuffer *iface, IRpcChannelBuffer *pChannel, + PRPC_MESSAGE pMsg, DWORD *pdwStubPhase ) +{ + /* Note pMsg is passed intact since RPCOLEMESSAGE is basically a RPC_MESSAGE. */ + + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + HRESULT r = IRpcStubBuffer_Invoke(This->base_stub, (RPCOLEMESSAGE*)pMsg, pChannel); + if(FAILED(r)) RpcRaiseException(r); + return; +} + +/*********************************************************************** + * NdrStubInitialize [RPCRT4.@] + */ +void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + LPRPCCHANNELBUFFER pRpcChannelBuffer) +{ + TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer); + NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor); + pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; +} + +/*********************************************************************** + * NdrStubGetBuffer [RPCRT4.@] + */ +void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER iface, + LPRPCCHANNELBUFFER pRpcChannelBuffer, + PMIDL_STUB_MESSAGE pStubMsg) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + HRESULT hr; + + TRACE("(%p, %p, %p)\n", This, pRpcChannelBuffer, pStubMsg); + + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + hr = IRpcChannelBuffer_GetBuffer(pRpcChannelBuffer, + (RPCOLEMESSAGE *)pStubMsg->RpcMsg, STUB_HEADER(This).piid); + if (FAILED(hr)) + { + RpcRaiseException(hr); + return; + } + + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; +} diff --git a/reactos/dll/win32/rpcrt4/epm_towers.h b/reactos/dll/win32/rpcrt4/epm_towers.h new file mode 100644 index 00000000000..9c58ff0c3dd --- /dev/null +++ b/reactos/dll/win32/rpcrt4/epm_towers.h @@ -0,0 +1,88 @@ +/* + * Endpoint Mapper Tower Definitions + * + * Copyright 2006 Robert Shearman (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#define EPM_PROTOCOL_DNET_NSP 0x04 +#define EPM_PROTOCOL_OSI_TP4 0x05 +#define EPM_PROTOCOL_OSI_CLNS 0x06 +#define EPM_PROTOCOL_TCP 0x07 +#define EPM_PROTOCOL_UDP 0x08 +#define EPM_PROTOCOL_IP 0x09 +#define EPM_PROTOCOL_NCADG 0x0a /* Connectionless RPC */ +#define EPM_PROTOCOL_NCACN 0x0b +#define EPM_PROTOCOL_NCALRPC 0x0c /* Local RPC */ +#define EPM_PROTOCOL_UUID 0x0d +#define EPM_PROTOCOL_IPX 0x0e +#define EPM_PROTOCOL_SMB 0x0f +#define EPM_PROTOCOL_PIPE 0x10 +#define EPM_PROTOCOL_NETBIOS 0x11 +#define EPM_PROTOCOL_NETBEUI 0x12 +#define EPM_PROTOCOL_SPX 0x13 +#define EPM_PROTOCOL_NB_IPX 0x14 /* NetBIOS over IPX */ +#define EPM_PROTOCOL_DSP 0x16 /* AppleTalk Data Stream Protocol */ +#define EPM_PROTOCOL_DDP 0x17 /* AppleTalk Data Datagram Protocol */ +#define EPM_PROTOCOL_APPLETALK 0x18 /* AppleTalk */ +#define EPM_PROTOCOL_VINES_SPP 0x1a +#define EPM_PROTOCOL_VINES_IPC 0x1b /* Inter Process Communication */ +#define EPM_PROTOCOL_STREETTALK 0x1c /* Vines Streettalk */ +#define EPM_PROTOCOL_HTTP 0x1f +#define EPM_PROTOCOL_UNIX_DS 0x20 /* Unix domain socket */ +#define EPM_PROTOCOL_NULL 0x21 + +#include + +typedef unsigned char u_int8; +typedef unsigned short u_int16; +typedef unsigned int u_int32; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + GUID uuid; + u_int16 major_version; + u_int16 count_rhs; + u_int16 minor_version; +} twr_uuid_floor_t; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + u_int16 count_rhs; + u_int16 port; +} twr_tcp_floor_t; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + u_int16 count_rhs; + u_int32 ipv4addr; +} twr_ipv4_floor_t; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + u_int16 count_rhs; +} twr_empty_floor_t; + +#include diff --git a/reactos/dll/win32/rpcrt4/ndr_clientserver.c b/reactos/dll/win32/rpcrt4/ndr_clientserver.c new file mode 100644 index 00000000000..07adb3f2005 --- /dev/null +++ b/reactos/dll/win32/rpcrt4/ndr_clientserver.c @@ -0,0 +1,208 @@ +/* + * MIDL proxy/stub stuff + * + * Copyright 2002 Ove Kåven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + */ + +#include +#include +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "ndr_misc.h" +#include "rpcndr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +/************************************************************************ + * NdrClientInitializeNew [RPCRT4.@] + */ +void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum ) +{ + TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n", + pRpcMessage, pStubMsg, pStubDesc, ProcNum); + + assert( pRpcMessage && pStubMsg && pStubDesc ); + + pRpcMessage->Handle = NULL; + pRpcMessage->ProcNum = ProcNum; + pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; + pRpcMessage->RpcFlags = 0; + pRpcMessage->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; + + pStubMsg->RpcMsg = pRpcMessage; + pStubMsg->BufferStart = NULL; + pStubMsg->BufferEnd = NULL; + pStubMsg->BufferLength = 0; + pStubMsg->IsClient = TRUE; + pStubMsg->ReuseBuffer = FALSE; + pStubMsg->pAllocAllNodesContext = NULL; + pStubMsg->pPointerQueueState = NULL; + pStubMsg->IgnoreEmbeddedPointers = 0; + pStubMsg->PointerBufferMark = NULL; + pStubMsg->fBufferValid = 0; + pStubMsg->uFlags = 0; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->StackTop = NULL; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->FullPtrRefId = 0; + pStubMsg->PointerLength = 0; + pStubMsg->fInDontFree = 0; + pStubMsg->fDontCallFreeInst = 0; + pStubMsg->fInOnlyParam = 0; + pStubMsg->fHasReturn = 0; + pStubMsg->fHasExtensions = 0; + pStubMsg->fHasNewCorrDesc = 0; + pStubMsg->fUnused = 0; + pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE; + pStubMsg->pvDestContext = NULL; + pStubMsg->pRpcChannelBuffer = NULL; + pStubMsg->pArrayInfo = NULL; + pStubMsg->dwStubPhase = 0; + /* FIXME: LowStackMark */ + pStubMsg->pAsyncMsg = NULL; + pStubMsg->pCorrInfo = NULL; + pStubMsg->pCorrMemory = NULL; + pStubMsg->pMemoryList = NULL; +} + +/*********************************************************************** + * NdrServerInitializeNew [RPCRT4.@] + */ +unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc ) +{ + TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc); + + assert( pRpcMsg && pStubMsg && pStubDesc ); + + /* not everyone allocates stack space for w2kReserved */ + memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); + + pStubMsg->ReuseBuffer = TRUE; + pStubMsg->IsClient = FALSE; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->RpcMsg = pRpcMsg; + pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; + pStubMsg->BufferLength = pRpcMsg->BufferLength; + pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength; + + /* FIXME: determine the proper return value */ + return NULL; +} + +/*********************************************************************** + * NdrGetBuffer [RPCRT4.@] + */ +unsigned char *WINAPI NdrGetBuffer(PMIDL_STUB_MESSAGE stubmsg, ULONG buflen, RPC_BINDING_HANDLE handle) +{ + TRACE("(stubmsg == ^%p, buflen == %u, handle == %p): wild guess.\n", stubmsg, buflen, handle); + + assert( stubmsg && stubmsg->RpcMsg ); + + /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ + stubmsg->RpcMsg->Handle = handle; + + stubmsg->RpcMsg->BufferLength = buflen; + if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) + return NULL; + + stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength; + return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer); +} +/*********************************************************************** + * NdrFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrFreeBuffer(PMIDL_STUB_MESSAGE pStubMsg) +{ + TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg); + I_RpcFreeBuffer(pStubMsg->RpcMsg); + pStubMsg->BufferLength = 0; + pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL); +} + +/************************************************************************ + * NdrSendReceive [RPCRT4.@] + */ +unsigned char *WINAPI NdrSendReceive( PMIDL_STUB_MESSAGE stubmsg, unsigned char *buffer ) +{ + RPC_STATUS status; + + TRACE("(stubmsg == ^%p, buffer == ^%p)\n", stubmsg, buffer); + + /* FIXME: how to handle errors? (raise exception?) */ + if (!stubmsg) { + ERR("NULL stub message. No action taken.\n"); + return NULL; + } + if (!stubmsg->RpcMsg) { + ERR("RPC Message not present in stub message. No action taken.\n"); + return NULL; + } + + stubmsg->RpcMsg->BufferLength = buffer - (unsigned char *)stubmsg->RpcMsg->Buffer; + status = I_RpcSendReceive(stubmsg->RpcMsg); + if (status != RPC_S_OK) + RpcRaiseException(status); + + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; + stubmsg->BufferEnd = stubmsg->BufferStart + stubmsg->BufferLength; + stubmsg->Buffer = stubmsg->BufferStart; + + /* FIXME: is this the right return value? */ + return NULL; +} + +/************************************************************************ + * NdrMapCommAndFaultStatus [RPCRT4.@] + */ +RPC_STATUS RPC_ENTRY NdrMapCommAndFaultStatus( PMIDL_STUB_MESSAGE pStubMsg, + ULONG *pCommStatus, + ULONG *pFaultStatus, + RPC_STATUS Status ) +{ + FIXME("(%p, %p, %p, %ld): stub\n", pStubMsg, pCommStatus, pFaultStatus, Status); + + *pCommStatus = 0; + *pFaultStatus = 0; + + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4/ndr_contexth.c b/reactos/dll/win32/rpcrt4/ndr_contexth.c deleted file mode 100644 index a798efc71e2..00000000000 --- a/reactos/dll/win32/rpcrt4/ndr_contexth.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Context Handle Functions - * - * Copyright 2006 Saveliy Tretiakov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "rpc.h" -#include "rpcndr.h" -#include "wine/debug.h" - -#include "rpc_binding.h" -#include "ndr_contexth.h" - -static SContextHandle *CtxList = NULL; - -static CRITICAL_SECTION CtxList_cs; -static CRITICAL_SECTION_DEBUG CtxList_cs_debug = -{ - 0, 0, &CtxList_cs, - { &CtxList_cs_debug.ProcessLocksList, &CtxList_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": CtxList_cs") } -}; -static CRITICAL_SECTION CtxList_cs = { &CtxList_cs_debug, -1, 0, 0, 0, 0 }; - -SContextHandle* RPCRT4_SrvAllocCtxHdl() -{ - SContextHandle *Hdl, *Tmp; - - if((Hdl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(SContextHandle)))==NULL) return NULL; - - EnterCriticalSection(&CtxList_cs); - - if(!CtxList) CtxList = Hdl; - else - { - for(Tmp = CtxList; Tmp->Next; Tmp = Tmp->Next); - Tmp->Next = Hdl; - Hdl->Prev = Tmp; - } - - LeaveCriticalSection(&CtxList_cs); - - return Hdl; -} - -void RPCRT4_SrvFreeCtxHdl(SContextHandle *Hdl) -{ - EnterCriticalSection(&CtxList_cs); - - if(Hdl->Prev && Hdl->Next) - { - ((SContextHandle*)Hdl->Prev)->Next = Hdl->Next; - ((SContextHandle*)Hdl->Next)->Prev = Hdl->Prev; - } - else if(Hdl->Next) - { - ((SContextHandle*)Hdl->Next)->Prev = NULL; - CtxList = (SContextHandle*)Hdl->Next; - } - else if(Hdl->Prev) - ((SContextHandle*)Hdl->Prev)->Next = NULL; - else CtxList = NULL; - - HeapFree(GetProcessHeap(), 0, Hdl); - LeaveCriticalSection(&CtxList_cs); -} - -SContextHandle* RPCRT4_SrvFindCtxHdl(ContextHandleNdr *CtxNdr) -{ - SContextHandle *Hdl, *Ret=NULL; - RPC_STATUS status; - EnterCriticalSection(&CtxList_cs); - - for(Hdl = CtxList; Hdl; Hdl = Hdl->Next) - if(UuidCompare(&Hdl->Ndr.uuid, &CtxNdr->uuid, &status)==0) - { - Ret = Hdl; - break; - } - - LeaveCriticalSection(&CtxList_cs); - return Ret; -} - -SContextHandle* RPCRT4_SrvUnmarshallCtxHdl(ContextHandleNdr *Ndr) -{ - SContextHandle *Hdl = NULL; - RPC_STATUS status; - - if(!Ndr) - { - if((Hdl = RPCRT4_SrvAllocCtxHdl())==NULL) - RpcRaiseException(ERROR_OUTOFMEMORY); - - UuidCreate(&Hdl->Ndr.uuid); - } - else if(!UuidIsNil(&Ndr->uuid, &status)) - Hdl = RPCRT4_SrvFindCtxHdl(Ndr); - - return Hdl; -} - -void RPCRT4_SrvMarshallCtxHdl(SContextHandle *Hdl, ContextHandleNdr *Ndr) -{ - if(!Hdl->Value) - { - RPCRT4_SrvFreeCtxHdl(Hdl); - ZeroMemory(Ndr, sizeof(ContextHandleNdr)); - } - else memcpy(Ndr, &Hdl->Ndr, sizeof(ContextHandleNdr)); -} - -void RPCRT4_DoContextRundownIfNeeded(RpcConnection *Conn) -{ - -} - -/*********************************************************************** - * NDRCContextBinding - */ -RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext) -{ - if(!CContext) - RpcRaiseException(ERROR_INVALID_HANDLE); - - return (RPC_BINDING_HANDLE)((CContextHandle*)CContext)->Binding; -} - -/*********************************************************************** - * NDRCContextMarshall - */ -void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff ) -{ - CContextHandle *ctx = (CContextHandle*)CContext; - memcpy(pBuff, &ctx->Ndr, sizeof(ContextHandleNdr)); -} - -/*********************************************************************** - * NdrClientContextMarshall - */ -void WINAPI NdrClientContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, - NDR_CCONTEXT ContextHandle, - int fCheck) -{ - if(!ContextHandle) - RpcRaiseException(ERROR_INVALID_HANDLE); - - NDRCContextMarshall(ContextHandle, pStubMsg->Buffer); - - pStubMsg->Buffer += sizeof(ContextHandleNdr); - -} - -/*********************************************************************** - * NDRCContextUnmarshall - */ -void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *pCContext, - RPC_BINDING_HANDLE hBinding, - void *pBuff, - unsigned long DataRepresentation ) -{ - CContextHandle *ctx = (CContextHandle*)*pCContext; - ContextHandleNdr *ndr = (ContextHandleNdr*)pBuff; - RPC_STATUS status; - - if(UuidIsNil(&ndr->uuid, &status)) - { - if(ctx) - { - RPCRT4_DestroyBinding(ctx->Binding); - HeapFree(GetProcessHeap(), 0, ctx); - } - *pCContext = NULL; - } - else - { - ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(CContextHandle)); - if(!ctx) RpcRaiseException(ERROR_OUTOFMEMORY); - - status = RpcBindingCopy(hBinding, (RPC_BINDING_HANDLE*) &ctx->Binding); - if(status != RPC_S_OK) RpcRaiseException(status); - - memcpy(&ctx->Ndr, ndr, sizeof(ContextHandleNdr)); - *pCContext = (NDR_CCONTEXT)ctx; - } -} - -/*********************************************************************** - * NdrClientContextUnmarshall - */ -void WINAPI NdrClientContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - NDR_CCONTEXT * pContextHandle, - RPC_BINDING_HANDLE BindHandle) -{ - - if(!pContextHandle || !BindHandle) - RpcRaiseException(ERROR_INVALID_HANDLE); - - NDRCContextUnmarshall(pContextHandle, - (CContextHandle*)BindHandle, - pStubMsg->Buffer, - pStubMsg->RpcMsg->DataRepresentation); - - pStubMsg->Buffer += sizeof(ContextHandleNdr); -} - -/*********************************************************************** - * RpcSmDestroyClientContext - */ -RPC_STATUS WINAPI RpcSmDestroyClientContext(void** ContextHandle) -{ - CContextHandle *ctx = (CContextHandle*)ContextHandle; - - if(!ctx) - return RPC_X_SS_CONTEXT_MISMATCH; - - RPCRT4_DestroyBinding(ctx->Binding); - HeapFree(GetProcessHeap(), 0, ctx); - *ContextHandle = NULL; - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcSsDestroyClientContext - */ -void WINAPI RpcSsDestroyClientContext(void** ContextHandle) -{ - RPC_STATUS status; - - status = RpcSmDestroyClientContext(ContextHandle); - - if(status != RPC_S_OK) - RpcRaiseException(status); -} - -/*********************************************************************** - * NdrContextHandleSize - */ -void WINAPI NdrContextHandleSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char* pMemory, - PFORMAT_STRING pFormat) -{ - FIXME("(%p, %p, %p): stub\n", pStubMsg, pMemory, pFormat); -} - -/*********************************************************************** - * NdrContextHandleInitialize - */ -NDR_SCONTEXT WINAPI NdrContextHandleInitialize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - FIXME("(%p, %p): stub\n", pStubMsg, pFormat); - return NULL; -} - -/*********************************************************************** - * NdrServerContextMarshall - */ -void WINAPI NdrServerContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, - NDR_SCONTEXT ContextHandle, - NDR_RUNDOWN RundownRoutine) -{ - SContextHandle *Hdl; - RpcBinding *Binding; - - if(!ContextHandle) - RpcRaiseException(ERROR_INVALID_HANDLE); - - Hdl = (SContextHandle*)ContextHandle; - Binding = (RpcBinding*)pStubMsg->RpcMsg->Handle; - Hdl->Rundown = RundownRoutine; - Hdl->Conn = Binding->FromConn; - RPCRT4_SrvMarshallCtxHdl(Hdl, (ContextHandleNdr*)pStubMsg->Buffer); - pStubMsg->Buffer += sizeof(ContextHandleNdr); -} - -/*********************************************************************** - * NdrServerContextUnmarshall - */ -NDR_SCONTEXT WINAPI NdrServerContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg) -{ - SContextHandle *Hdl; - - Hdl = RPCRT4_SrvUnmarshallCtxHdl((ContextHandleNdr*)pStubMsg->Buffer); - return (NDR_SCONTEXT)Hdl; -} - -/*********************************************************************** - * NdrServerContextNewMarshall - */ -void WINAPI NdrServerContextNewMarshall(PMIDL_STUB_MESSAGE pStubMsg, - NDR_SCONTEXT ContextHandle, - NDR_RUNDOWN RundownRoutine, - PFORMAT_STRING pFormat) -{ - FIXME("(%p, %p, %p, %p): stub\n", pStubMsg, ContextHandle, RundownRoutine, pFormat); -} - -/*********************************************************************** - * NdrServerContextNewUnmarshall - */ -NDR_SCONTEXT WINAPI NdrServerContextNewUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - FIXME("(%p, %p): stub\n", pStubMsg, pFormat); - return NULL; -} - -/*********************************************************************** - * NDRSContextMarshall - */ -void WINAPI NDRSContextMarshall(IN NDR_SCONTEXT CContext, - OUT void *pBuff, - IN NDR_RUNDOWN userRunDownIn) -{ - SContextHandle *Hdl; - - if(!CContext) - RpcRaiseException(ERROR_INVALID_HANDLE); - - Hdl = (SContextHandle*)CContext; - Hdl->Rundown = userRunDownIn; - RPCRT4_SrvMarshallCtxHdl(Hdl, (ContextHandleNdr*)pBuff); -} - -/*********************************************************************** - * NDRSContextUnmarshall - */ -NDR_SCONTEXT WINAPI NDRSContextUnmarshall(IN void *pBuff, - IN unsigned long DataRepresentation) -{ - return (NDR_SCONTEXT) RPCRT4_SrvUnmarshallCtxHdl((ContextHandleNdr*)pBuff); -} - -/*********************************************************************** - * NDRSContextMarshallEx - */ -void WINAPI NDRSContextMarshallEx(IN RPC_BINDING_HANDLE BindingHandle, - IN NDR_SCONTEXT CContext, - OUT void *pBuff, - IN NDR_RUNDOWN userRunDownIn) -{ - FIXME("stub\n"); -} - -/*********************************************************************** - * NDRSContextUnmarshallEx - */ -NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(IN RPC_BINDING_HANDLE BindingHandle, - IN void *pBuff, - IN unsigned long DataRepresentation) -{ - FIXME("stub\n"); - return NULL; -} diff --git a/reactos/dll/win32/rpcrt4/ndr_contexth.h b/reactos/dll/win32/rpcrt4/ndr_contexth.h deleted file mode 100644 index c953f8f3612..00000000000 --- a/reactos/dll/win32/rpcrt4/ndr_contexth.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Context Handle Functions - * - * Copyright 2006 Saveliy Tretiakov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef __WINE_NDR_CONTEXTH_H -#define __WINE_NDR_CONTEXTH_H - -#include "wine/rpcss_shared.h" - -typedef struct _ContextHandleNdr -{ - UINT attributes; - UUID uuid; -} ContextHandleNdr; - -typedef struct _CContextHandle -{ - RpcBinding *Binding; - ContextHandleNdr Ndr; -} CContextHandle; - -/* - Keep this structure compatible with public rpcndr.h - declaration, otherwise NDRSContextValue macro won't work. - typedef struct { - void *pad[2]; - void *userContext; - } *NDR_SCONTEXT; -*/ - -typedef struct _SContextHandle -{ - PVOID Prev; - PVOID Next; - PVOID Value; - NDR_RUNDOWN Rundown; - RpcConnection *Conn; - ContextHandleNdr Ndr; -} SContextHandle; - -void RPCRT4_DoContextRundownIfNeeded(RpcConnection *Conn); - -#endif //__WINE_NDR_CONTEXTH_H diff --git a/reactos/dll/win32/rpcrt4/ndr_fullpointer.c b/reactos/dll/win32/rpcrt4/ndr_fullpointer.c new file mode 100644 index 00000000000..f6945193760 --- /dev/null +++ b/reactos/dll/win32/rpcrt4/ndr_fullpointer.c @@ -0,0 +1,233 @@ +/* + * Full Pointer Translation Routines + * + * Copyright 2006 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +PFULL_PTR_XLAT_TABLES WINAPI NdrFullPointerXlatInit(ULONG NumberOfPointers, + XLAT_SIDE XlatSide) +{ + ULONG NumberOfBuckets; + PFULL_PTR_XLAT_TABLES pXlatTables = HeapAlloc(GetProcessHeap(), 0, sizeof(*pXlatTables)); + + TRACE("(%d, %d)\n", NumberOfPointers, XlatSide); + + if (!NumberOfPointers) NumberOfPointers = 512; + NumberOfBuckets = ((NumberOfPointers + 3) & ~3) - 1; + + pXlatTables->RefIdToPointer.XlatTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(void *) * NumberOfPointers); + pXlatTables->RefIdToPointer.StateTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(unsigned char) * NumberOfPointers); + pXlatTables->RefIdToPointer.NumberOfEntries = NumberOfPointers; + + TRACE("NumberOfBuckets = %d\n", NumberOfBuckets); + pXlatTables->PointerToRefId.XlatTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(PFULL_PTR_TO_REFID_ELEMENT) * NumberOfBuckets); + pXlatTables->PointerToRefId.NumberOfBuckets = NumberOfBuckets; + pXlatTables->PointerToRefId.HashMask = NumberOfBuckets - 1; + + pXlatTables->NextRefId = 1; + pXlatTables->XlatSide = XlatSide; + + return pXlatTables; +} + +void WINAPI NdrFullPointerXlatFree(PFULL_PTR_XLAT_TABLES pXlatTables) +{ + TRACE("(%p)\n", pXlatTables); + + HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.XlatTable); + HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.StateTable); + HeapFree(GetProcessHeap(), 0, pXlatTables->PointerToRefId.XlatTable); + + HeapFree(GetProcessHeap(), 0, pXlatTables); +} + +static void expand_pointer_table_if_necessary(PFULL_PTR_XLAT_TABLES pXlatTables, ULONG RefId) +{ + if (RefId >= pXlatTables->RefIdToPointer.NumberOfEntries) + { + pXlatTables->RefIdToPointer.NumberOfEntries = RefId * 2; + pXlatTables->RefIdToPointer.XlatTable = + HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pXlatTables->RefIdToPointer.XlatTable, + sizeof(void *) * pXlatTables->RefIdToPointer.NumberOfEntries); + pXlatTables->RefIdToPointer.StateTable = + HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pXlatTables->RefIdToPointer.StateTable, + sizeof(unsigned char) * pXlatTables->RefIdToPointer.NumberOfEntries); + + if (!pXlatTables->RefIdToPointer.XlatTable || !pXlatTables->RefIdToPointer.StateTable) + pXlatTables->RefIdToPointer.NumberOfEntries = 0; + } +} + +int WINAPI NdrFullPointerQueryPointer(PFULL_PTR_XLAT_TABLES pXlatTables, + void *pPointer, unsigned char QueryType, + ULONG *pRefId ) +{ + ULONG Hash = 0; + int i; + PFULL_PTR_TO_REFID_ELEMENT XlatTableEntry; + + TRACE("(%p, %p, %d, %p)\n", pXlatTables, pPointer, QueryType, pRefId); + + if (!pPointer) + { + *pRefId = 0; + return 1; + } + + /* simple hashing algorithm, don't know whether it matches native */ + for (i = 0; i < sizeof(pPointer); i++) + Hash = (Hash * 3) ^ ((unsigned char *)&pPointer)[i]; + + XlatTableEntry = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + for (; XlatTableEntry; XlatTableEntry = XlatTableEntry->Next) + if (pPointer == XlatTableEntry->Pointer) + { + *pRefId = XlatTableEntry->RefId; + if (XlatTableEntry->State & QueryType) + return 1; + XlatTableEntry->State |= QueryType; + return 0; + } + + XlatTableEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(*XlatTableEntry)); + XlatTableEntry->Next = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + XlatTableEntry->Pointer = pPointer; + XlatTableEntry->RefId = *pRefId = pXlatTables->NextRefId++; + XlatTableEntry->State = QueryType; + pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask] = XlatTableEntry; + + /* insert pointer into mapping table */ + expand_pointer_table_if_necessary(pXlatTables, XlatTableEntry->RefId); + if (pXlatTables->RefIdToPointer.NumberOfEntries > XlatTableEntry->RefId) + { + pXlatTables->RefIdToPointer.XlatTable[XlatTableEntry->RefId] = pPointer; + pXlatTables->RefIdToPointer.StateTable[XlatTableEntry->RefId] = QueryType; + } + + return 0; +} + +int WINAPI NdrFullPointerQueryRefId(PFULL_PTR_XLAT_TABLES pXlatTables, + ULONG RefId, unsigned char QueryType, + void **ppPointer) +{ + TRACE("(%p, 0x%x, %d, %p)\n", pXlatTables, RefId, QueryType, ppPointer); + + expand_pointer_table_if_necessary(pXlatTables, RefId); + + pXlatTables->NextRefId = max(RefId + 1, pXlatTables->NextRefId); + + if (pXlatTables->RefIdToPointer.NumberOfEntries > RefId) + { + *ppPointer = pXlatTables->RefIdToPointer.XlatTable[RefId]; + if (QueryType) + { + if (pXlatTables->RefIdToPointer.StateTable[RefId] & QueryType) + return 1; + pXlatTables->RefIdToPointer.StateTable[RefId] |= QueryType; + return 0; + } + else + return 0; + } + *ppPointer = NULL; + return 0; +} + +void WINAPI NdrFullPointerInsertRefId(PFULL_PTR_XLAT_TABLES pXlatTables, + ULONG RefId, void *pPointer) +{ + ULONG Hash = 0; + int i; + PFULL_PTR_TO_REFID_ELEMENT XlatTableEntry; + + TRACE("(%p, 0x%x, %p)\n", pXlatTables, RefId, pPointer); + + /* simple hashing algorithm, don't know whether it matches native */ + for (i = 0; i < sizeof(pPointer); i++) + Hash = (Hash * 3) ^ ((unsigned char *)&pPointer)[i]; + + XlatTableEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(*XlatTableEntry)); + XlatTableEntry->Next = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + XlatTableEntry->Pointer = pPointer; + XlatTableEntry->RefId = RefId; + XlatTableEntry->State = 0; + pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask] = XlatTableEntry; + + /* insert pointer into mapping table */ + expand_pointer_table_if_necessary(pXlatTables, RefId); + if (pXlatTables->RefIdToPointer.NumberOfEntries > RefId) + pXlatTables->RefIdToPointer.XlatTable[XlatTableEntry->RefId] = pPointer; +} + +int WINAPI NdrFullPointerFree(PFULL_PTR_XLAT_TABLES pXlatTables, void *Pointer) +{ + ULONG Hash = 0; + int i; + PFULL_PTR_TO_REFID_ELEMENT XlatTableEntry; + ULONG RefId = 0; + + TRACE("(%p, %p)\n", pXlatTables, Pointer); + + if (!Pointer) + return 1; + + /* simple hashing algorithm, don't know whether it matches native */ + for (i = 0; i < sizeof(Pointer); i++) + Hash = (Hash * 3) ^ ((unsigned char *)&Pointer)[i]; + + XlatTableEntry = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + for (; XlatTableEntry; XlatTableEntry = XlatTableEntry->Next) + if (Pointer == XlatTableEntry->Pointer) + { + if (XlatTableEntry->State & 0x20) + return 0; + XlatTableEntry->State |= 0x20; + RefId = XlatTableEntry->RefId; + break; + } + + if (!XlatTableEntry) + return 0; + + if (pXlatTables->RefIdToPointer.NumberOfEntries > RefId) + { + pXlatTables->RefIdToPointer.StateTable[RefId] |= 0x20; + return 1; + } + + return 0; +} diff --git a/reactos/dll/win32/rpcrt4/ndr_marshall.c b/reactos/dll/win32/rpcrt4/ndr_marshall.c index c0c68768b6b..ad95b53abe2 100644 --- a/reactos/dll/win32/rpcrt4/ndr_marshall.c +++ b/reactos/dll/win32/rpcrt4/ndr_marshall.c @@ -2,6 +2,7 @@ * NDR data marshalling * * Copyright 2002 Greg Turner + * Copyright 2003-2006 CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -15,11 +16,18 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions + * - Non-conformant strings + * - String structs + * - Encapsulated unions + * - Byte count pointers + * - transmit_as/represent as + * - Multi-dimensional arrays + * - Conversion functions (NdrConvert) + * - Checks for integer addition overflow + * - Checks for out-of-memory conditions */ #include @@ -40,13 +48,10 @@ #include "wine/rpcfc.h" #include "wine/debug.h" - -#include "rpc_binding.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); -#define BUFFER_PARANOIA 20 - #if defined(__i386__) # define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ (*((UINT32 *)(pchar)) = (uint32)) @@ -92,15 +97,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); LITTLE_ENDIAN_UINT32_READ(pchar) #endif -/* _Align must be the desired alignment minus 1, - * e.g. ALIGN_LENGTH(len, 3) to align on a dword boundary. */ -#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) +/* _Align must be the desired alignment, + * e.g. ALIGN_LENGTH(len, 4) to align on a dword boundary. */ +#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align)-1)&~((_Align)-1)) #define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) #define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) #define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) #define STD_OVERFLOW_CHECK(_Msg) do { \ - TRACE("buffer=%d/%ld\n", _Msg->Buffer - (unsigned char *)_Msg->RpcMsg->Buffer, _Msg->BufferLength); \ + TRACE("buffer=%d/%d\n", _Msg->Buffer - (unsigned char *)_Msg->RpcMsg->Buffer, _Msg->BufferLength); \ if (_Msg->Buffer > (unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength) \ ERR("buffer overflow %d bytes\n", _Msg->Buffer - ((unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength)); \ } while (0) @@ -112,9 +117,9 @@ static unsigned char *WINAPI NdrBaseTypeMarshall(PMIDL_STUB_MESSAGE, unsigned ch static unsigned char *WINAPI NdrBaseTypeUnmarshall(PMIDL_STUB_MESSAGE, unsigned char **, PFORMAT_STRING, unsigned char); static void WINAPI NdrBaseTypeBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); static void WINAPI NdrBaseTypeFree(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); -static unsigned long WINAPI NdrBaseTypeMemorySize(PMIDL_STUB_MESSAGE, PFORMAT_STRING); +static ULONG WINAPI NdrBaseTypeMemorySize(PMIDL_STUB_MESSAGE, PFORMAT_STRING); -NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { +const NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { 0, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, @@ -143,7 +148,7 @@ NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { /* 0x2a */ NdrEncapsulatedUnionMarshall, NdrNonEncapsulatedUnionMarshall, - 0, + NdrByteCountPointerMarshall, NdrXmitOrRepAsMarshall, NdrXmitOrRepAsMarshall, /* 0x2f */ NdrInterfacePointerMarshall, @@ -151,7 +156,7 @@ NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { 0, 0, 0, 0, NdrUserMarshalMarshall }; -NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { +const NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { 0, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, @@ -180,7 +185,7 @@ NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { /* 0x2a */ NdrEncapsulatedUnionUnmarshall, NdrNonEncapsulatedUnionUnmarshall, - 0, + NdrByteCountPointerUnmarshall, NdrXmitOrRepAsUnmarshall, NdrXmitOrRepAsUnmarshall, /* 0x2f */ NdrInterfacePointerUnmarshall, @@ -188,7 +193,7 @@ NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { 0, 0, 0, 0, NdrUserMarshalUnmarshall }; -NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { +const NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { 0, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, @@ -217,7 +222,7 @@ NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { /* 0x2a */ NdrEncapsulatedUnionBufferSize, NdrNonEncapsulatedUnionBufferSize, - 0, + NdrByteCountPointerBufferSize, NdrXmitOrRepAsBufferSize, NdrXmitOrRepAsBufferSize, /* 0x2f */ NdrInterfacePointerBufferSize, @@ -225,7 +230,7 @@ NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { 0, 0, 0, 0, NdrUserMarshalBufferSize }; -NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { +const NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { 0, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, @@ -238,24 +243,31 @@ NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { NdrPointerMemorySize, NdrPointerMemorySize, /* 0x15 */ NdrSimpleStructMemorySize, NdrSimpleStructMemorySize, - 0, 0, 0, + NdrConformantStructMemorySize, NdrConformantStructMemorySize, + NdrConformantVaryingStructMemorySize, NdrComplexStructMemorySize, /* 0x1b */ - NdrConformantArrayMemorySize, 0, 0, 0, 0, 0, + NdrConformantArrayMemorySize, + NdrConformantVaryingArrayMemorySize, + NdrFixedArrayMemorySize, NdrFixedArrayMemorySize, + NdrVaryingArrayMemorySize, NdrVaryingArrayMemorySize, NdrComplexArrayMemorySize, /* 0x22 */ NdrConformantStringMemorySize, 0, 0, NdrConformantStringMemorySize, NdrNonConformantStringMemorySize, 0, 0, 0, /* 0x2a */ - 0, 0, 0, 0, 0, + NdrEncapsulatedUnionMemorySize, + NdrNonEncapsulatedUnionMemorySize, + NdrByteCountPointerMemorySize, + NdrXmitOrRepAsMemorySize, NdrXmitOrRepAsMemorySize, /* 0x2f */ NdrInterfacePointerMemorySize, /* 0xb0 */ 0, 0, 0, 0, NdrUserMarshalMemorySize }; -NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { +const NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { 0, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, @@ -308,8 +320,9 @@ static inline BOOL IsConformanceOrVariancePresent(PFORMAT_STRING pFormat) return (*(const ULONG *)pFormat != -1); } -PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +static PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) { + ALIGN_POINTER(pStubMsg->Buffer, 4); pStubMsg->MaxCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); pStubMsg->Buffer += 4; TRACE("unmarshalled conformance is %ld\n", pStubMsg->MaxCount); @@ -319,21 +332,31 @@ PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pForm return pFormat+4; } -static inline PFORMAT_STRING ReadVariance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +static inline PFORMAT_STRING ReadVariance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat, ULONG MaxValue) { - if (!IsConformanceOrVariancePresent(pFormat)) + if (pFormat && !IsConformanceOrVariancePresent(pFormat)) { pStubMsg->Offset = 0; pStubMsg->ActualCount = pStubMsg->MaxCount; goto done; } + ALIGN_POINTER(pStubMsg->Buffer, 4); pStubMsg->Offset = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); pStubMsg->Buffer += 4; - TRACE("offset is %ld\n", pStubMsg->Offset); + TRACE("offset is %d\n", pStubMsg->Offset); pStubMsg->ActualCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); pStubMsg->Buffer += 4; - TRACE("variance is %ld\n", pStubMsg->ActualCount); + TRACE("variance is %d\n", pStubMsg->ActualCount); + + if ((pStubMsg->ActualCount > MaxValue) || + (pStubMsg->ActualCount + pStubMsg->Offset > MaxValue)) + { + ERR("invalid array bound(s): ActualCount = %d, Offset = %d, MaxValue = %d\n", + pStubMsg->ActualCount, pStubMsg->Offset, MaxValue); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } done: if (pStubMsg->fHasNewCorrDesc) @@ -342,12 +365,44 @@ done: return pFormat+4; } +/* writes the conformance value to the buffer */ +static inline void WriteConformance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_POINTER(pStubMsg->Buffer, 4); + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->MaxCount); + pStubMsg->Buffer += 4; +} + +/* writes the variance values to the buffer */ +static inline void WriteVariance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_POINTER(pStubMsg->Buffer, 4); + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->Offset); + pStubMsg->Buffer += 4; + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->ActualCount); + pStubMsg->Buffer += 4; +} + +/* requests buffer space for the conformance value */ +static inline void SizeConformance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 4; +} + +/* requests buffer space for the variance values */ +static inline void SizeVariance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 8; +} + PFORMAT_STRING ComputeConformanceOrVariance( MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, - PFORMAT_STRING pFormat, ULONG_PTR def, ULONG *pCount) + PFORMAT_STRING pFormat, ULONG_PTR def, ULONG_PTR *pCount) { BYTE dtype = pFormat[0] & 0xf; - short ofs = *(short *)&pFormat[2]; + short ofs = *(const short *)&pFormat[2]; LPVOID ptr = NULL; DWORD data = 0; @@ -360,16 +415,16 @@ PFORMAT_STRING ComputeConformanceOrVariance( switch (pFormat[0] & 0xf0) { case RPC_FC_NORMAL_CONFORMANCE: TRACE("normal conformance, ofs=%d\n", ofs); - ptr = pMemory + ofs; + ptr = pMemory; break; case RPC_FC_POINTER_CONFORMANCE: TRACE("pointer conformance, ofs=%d\n", ofs); - ptr = pStubMsg->Memory + ofs; + ptr = pStubMsg->Memory; break; case RPC_FC_TOP_LEVEL_CONFORMANCE: TRACE("toplevel conformance, ofs=%d\n", ofs); if (pStubMsg->StackTop) { - ptr = pStubMsg->StackTop + ofs; + ptr = pStubMsg->StackTop; } else { /* -Os mode, *pCount is already set */ @@ -378,13 +433,13 @@ PFORMAT_STRING ComputeConformanceOrVariance( break; case RPC_FC_CONSTANT_CONFORMANCE: data = ofs | ((DWORD)pFormat[1] << 16); - TRACE("constant conformance, val=%ld\n", data); + TRACE("constant conformance, val=%d\n", data); *pCount = data; goto finish_conf; case RPC_FC_TOP_LEVEL_MULTID_CONFORMANCE: FIXME("toplevel multidimensional conformance, ofs=%d\n", ofs); if (pStubMsg->StackTop) { - ptr = pStubMsg->StackTop + ofs; + ptr = pStubMsg->StackTop; } else { /* ? */ @@ -397,7 +452,7 @@ PFORMAT_STRING ComputeConformanceOrVariance( switch (pFormat[1]) { case RPC_FC_DEREFERENCE: - ptr = *(LPVOID*)ptr; + ptr = *(LPVOID*)((char *)ptr + ofs); break; case RPC_FC_CALLBACK: { @@ -409,9 +464,13 @@ PFORMAT_STRING ComputeConformanceOrVariance( pStubMsg->StubDesc->apfnExprEval[ofs](pStubMsg); pStubMsg->StackTop = old_stack_top; + + /* the callback function always stores the computed value in MaxCount */ + *pCount = pStubMsg->MaxCount; goto finish_conf; } default: + ptr = (char *)ptr + ofs; break; } @@ -426,9 +485,11 @@ PFORMAT_STRING ComputeConformanceOrVariance( case RPC_FC_USHORT: data = *(USHORT*)ptr; break; + case RPC_FC_CHAR: case RPC_FC_SMALL: data = *(CHAR*)ptr; break; + case RPC_FC_BYTE: case RPC_FC_USMALL: data = *(UCHAR*)ptr; break; @@ -436,15 +497,25 @@ PFORMAT_STRING ComputeConformanceOrVariance( FIXME("unknown conformance data type %x\n", dtype); goto done_conf_grab; } - TRACE("dereferenced data type %x at %p, got %ld\n", dtype, ptr, data); + TRACE("dereferenced data type %x at %p, got %d\n", dtype, ptr, data); done_conf_grab: switch (pFormat[1]) { + case RPC_FC_DEREFERENCE: /* already handled */ case 0: /* no op */ *pCount = data; break; - case RPC_FC_DEREFERENCE: - /* already handled */ + case RPC_FC_ADD_1: + *pCount = data + 1; + break; + case RPC_FC_SUB_1: + *pCount = data - 1; + break; + case RPC_FC_MULT_2: + *pCount = data * 2; + break; + case RPC_FC_DIV_2: + *pCount = data / 2; break; default: FIXME("unknown conformance op %d\n", pFormat[1]); @@ -459,6 +530,19 @@ finish_conf: return pFormat+4; } +/* multiply two numbers together, raising an RPC_S_INVALID_BOUND exception if + * the result overflows 32-bits */ +static inline ULONG safe_multiply(ULONG a, ULONG b) +{ + ULONGLONG ret = (ULONGLONG)a * b; + if (ret > 0xffffffff) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return 0; + } + return ret; +} + /* * NdrConformantString: @@ -483,25 +567,18 @@ finish_conf: unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pszMessage, PFORMAT_STRING pFormat) { - unsigned long len, esize; - unsigned char *c; + ULONG esize, size; TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat); - assert(pFormat); - if (pszMessage == NULL) { - TRACE("string=%s\n", debugstr_a(pszMessage)); - len = 0; - esize = 0; - } - else if (*pFormat == RPC_FC_C_CSTRING) { - TRACE("string=%s\n", debugstr_a(pszMessage)); - len = strlen(pszMessage)+1; + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a((char*)pszMessage)); + pStubMsg->ActualCount = strlen((char*)pszMessage)+1; esize = 1; } else if (*pFormat == RPC_FC_C_WSTRING) { TRACE("string=%s\n", debugstr_w((LPWSTR)pszMessage)); - len = strlenW((LPWSTR)pszMessage)+1; + pStubMsg->ActualCount = strlenW((LPWSTR)pszMessage)+1; esize = 2; } else { @@ -510,23 +587,17 @@ unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, return NULL; } - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); - } + if (pFormat[1] == RPC_FC_STRING_SIZED) + pFormat = ComputeConformance(pStubMsg, pszMessage, pFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + pStubMsg->Offset = 0; + WriteConformance(pStubMsg); + WriteVariance(pStubMsg); - assert( (pStubMsg->BufferLength >= (len*esize + 13)) && (pStubMsg->Buffer != NULL) ); - - c = pStubMsg->Buffer; - memset(c, 0, 12); - NDR_LOCAL_UINT32_WRITE(c, len); /* max length: strlen + 1 (for '\0') */ - c += 8; /* offset: 0 */ - NDR_LOCAL_UINT32_WRITE(c, len); /* actual length: (same) */ - c += 4; - if (len != 0) { - memcpy(c, pszMessage, len*esize); /* the string itself */ - c += len*esize; - } - pStubMsg->Buffer = c; + size = safe_multiply(esize, pStubMsg->ActualCount); + memcpy(pStubMsg->Buffer, pszMessage, size); /* the string itself */ + pStubMsg->Buffer += size; STD_OVERFLOW_CHECK(pStubMsg); @@ -540,44 +611,47 @@ unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat) { + ULONG esize; + TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat); - assert(pFormat); - if (pMemory == NULL) { - /* we need 12 octets for the [maxlen, offset, len] DWORDS */ - TRACE("string=NULL\n"); - pStubMsg->BufferLength += 12 + BUFFER_PARANOIA; - } - else if (*pFormat == RPC_FC_C_CSTRING) { - /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 1 octet for '\0' */ + SizeConformance(pStubMsg); + SizeVariance(pStubMsg); + + if (*pFormat == RPC_FC_C_CSTRING) { TRACE("string=%s\n", debugstr_a((char*)pMemory)); - pStubMsg->BufferLength += strlen((char*)pMemory) + 13 + BUFFER_PARANOIA; + pStubMsg->ActualCount = strlen((char*)pMemory)+1; + esize = 1; } else if (*pFormat == RPC_FC_C_WSTRING) { - /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 2 octets for L'\0' */ TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory)); - pStubMsg->BufferLength += strlenW((LPWSTR)pMemory)*2 + 14 + BUFFER_PARANOIA; + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory)+1; + esize = 2; } else { ERR("Unhandled string type: %#x\n", *pFormat); /* FIXME: raise an exception */ + return; } - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); - } + if (pFormat[1] == RPC_FC_STRING_SIZED) + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + + pStubMsg->BufferLength += safe_multiply(esize, pStubMsg->ActualCount); } /************************************************************************ * NdrConformantStringMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) { - unsigned long rslt = 0; + ULONG rslt = 0; + + FIXME("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat); - TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat); - assert(pStubMsg && pFormat); if (*pFormat == RPC_FC_C_CSTRING) { @@ -595,7 +669,7 @@ unsigned long WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, FIXME("sized string format=%d\n", pFormat[1]); } - TRACE(" --> %lu\n", rslt); + TRACE(" --> %u\n", rslt); return rslt; } @@ -605,18 +679,15 @@ unsigned long WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc ) { - unsigned long len, esize, ofs; + ULONG bufsize, memsize, esize, i; TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n", pStubMsg, *ppMemory, pFormat, fMustAlloc); assert(pFormat && ppMemory && pStubMsg); - pStubMsg->Buffer += 4; - ofs = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; - len = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; + ReadConformance(pStubMsg, NULL); + ReadVariance(pStubMsg, NULL, pStubMsg->MaxCount); if (*pFormat == RPC_FC_C_CSTRING) esize = 1; else if (*pFormat == RPC_FC_C_WSTRING) esize = 2; @@ -626,16 +697,31 @@ unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg esize = 0; } - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); + memsize = safe_multiply(esize, pStubMsg->MaxCount); + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + /* strings must always have null terminating bytes */ + if (bufsize < esize) + { + ERR("invalid string length of %d\n", pStubMsg->ActualCount); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; } + for (i = bufsize - esize; i < bufsize; i++) + if (pStubMsg->Buffer[i] != 0) + { + ERR("string not null-terminated at byte position %d, data is 0x%x\n", + i, pStubMsg->Buffer[i]); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, len*esize + BUFFER_PARANOIA); + *ppMemory = NdrAllocate(pStubMsg, memsize); - memcpy(*ppMemory, pStubMsg->Buffer, len*esize); + memcpy(*ppMemory, pStubMsg->Buffer, bufsize); - pStubMsg->Buffer += len*esize; + pStubMsg->Buffer += bufsize; if (*pFormat == RPC_FC_C_CSTRING) { TRACE("string=%s\n", debugstr_a((char*)*ppMemory)); @@ -683,7 +769,7 @@ void WINAPI NdrNonConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrNonConformantStringMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrNonConformantStringMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrNonConformantStringMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { FIXME("stub\n"); @@ -706,9 +792,9 @@ static inline void dump_pointer_attr(unsigned char attr) } /*********************************************************************** - * PointerMarshall + * PointerMarshall [internal] */ -void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, +static void PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *Buffer, unsigned char *Pointer, PFORMAT_STRING pFormat) @@ -716,16 +802,14 @@ void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned type = pFormat[0], attr = pFormat[1]; PFORMAT_STRING desc; NDR_MARSHALL m; + ULONG pointer_id; + int pointer_needs_marshaling; TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat); TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); pFormat += 2; if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - Pointer = *(unsigned char**)Pointer; - TRACE("deref => %p\n", Pointer); - } switch (type) { case RPC_FC_RP: /* ref pointer (always non-null) */ @@ -733,22 +817,37 @@ void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, if (!Pointer) RpcRaiseException(RPC_X_NULL_REF_POINTER); #endif + pointer_needs_marshaling = 1; break; case RPC_FC_UP: /* unique pointer */ case RPC_FC_OP: /* object pointer - same as unique here */ - TRACE("writing %p to buffer\n", Pointer); - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, (unsigned long)Pointer); - pStubMsg->Buffer += 4; + if (Pointer) + pointer_needs_marshaling = 1; + else + pointer_needs_marshaling = 0; + pointer_id = (ULONG)Pointer; + TRACE("writing 0x%08x to buffer\n", pointer_id); + NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id); break; case RPC_FC_FP: + pointer_needs_marshaling = !NdrFullPointerQueryPointer( + pStubMsg->FullPtrXlatTables, Pointer, 1, &pointer_id); + TRACE("writing 0x%08x to buffer\n", pointer_id); + NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id); + break; default: FIXME("unhandled ptr type=%02x\n", type); RpcRaiseException(RPC_X_BAD_STUB_DATA); + return; } TRACE("calling marshaller for type 0x%x\n", (int)*desc); - if (Pointer) { + if (pointer_needs_marshaling) { + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } m = NdrMarshaller[*desc & NDR_TABLE_MASK]; if (m) m(pStubMsg, Pointer, desc); else FIXME("no marshaller for data type=%02x\n", *desc); @@ -758,9 +857,9 @@ void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, } /*********************************************************************** - * PointerUnmarshall + * PointerUnmarshall [internal] */ -void WINAPI PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, +static void PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *Buffer, unsigned char **pPointer, PFORMAT_STRING pFormat, @@ -770,81 +869,115 @@ void WINAPI PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING desc; NDR_UNMARSHALL m; DWORD pointer_id = 0; + int pointer_needs_unmarshaling; TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pFormat, fMustAlloc); TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); pFormat += 2; if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - pPointer = *(unsigned char***)pPointer; - TRACE("deref => %p\n", pPointer); - } switch (type) { case RPC_FC_RP: /* ref pointer (always non-null) */ - pointer_id = ~0UL; + pointer_needs_unmarshaling = 1; break; case RPC_FC_UP: /* unique pointer */ - pointer_id = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; + pointer_id = NDR_LOCAL_UINT32_READ(Buffer); + TRACE("pointer_id is 0x%08x\n", pointer_id); + if (pointer_id) + pointer_needs_unmarshaling = 1; + else { + *pPointer = NULL; + pointer_needs_unmarshaling = 0; + } break; case RPC_FC_OP: /* object pointer - we must free data before overwriting it */ - pointer_id = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; - if (*pPointer) + pointer_id = NDR_LOCAL_UINT32_READ(Buffer); + TRACE("pointer_id is 0x%08x\n", pointer_id); + if (!fMustAlloc && *pPointer) + { FIXME("free object pointer %p\n", *pPointer); + *pPointer = NULL; + } + if (pointer_id) + pointer_needs_unmarshaling = 1; + else + pointer_needs_unmarshaling = 0; break; case RPC_FC_FP: + pointer_id = NDR_LOCAL_UINT32_READ(Buffer); + TRACE("pointer_id is 0x%08x\n", pointer_id); + pointer_needs_unmarshaling = !NdrFullPointerQueryRefId( + pStubMsg->FullPtrXlatTables, pointer_id, 1, (void **)pPointer); + break; default: FIXME("unhandled ptr type=%02x\n", type); RpcRaiseException(RPC_X_BAD_STUB_DATA); + return; } - if (pointer_id) { + if (pointer_needs_unmarshaling) { + if (attr & RPC_FC_P_DEREF) { + if (!*pPointer || fMustAlloc) + *pPointer = NdrAllocate(pStubMsg, sizeof(void *)); + pPointer = *(unsigned char***)pPointer; + TRACE("deref => %p\n", pPointer); + } m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; if (m) m(pStubMsg, pPointer, desc, fMustAlloc); else FIXME("no unmarshaller for data type=%02x\n", *desc); + + if (type == RPC_FC_FP) + NdrFullPointerInsertRefId(pStubMsg->FullPtrXlatTables, pointer_id, + *pPointer); } TRACE("pointer=%p\n", *pPointer); } /*********************************************************************** - * PointerBufferSize + * PointerBufferSize [internal] */ -void WINAPI PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, +static void PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *Pointer, PFORMAT_STRING pFormat) { unsigned type = pFormat[0], attr = pFormat[1]; PFORMAT_STRING desc; NDR_BUFFERSIZE m; + int pointer_needs_sizing; + ULONG pointer_id; TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); - TRACE("type=%d, attr=%d\n", type, attr); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); pFormat += 2; if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - Pointer = *(unsigned char**)Pointer; - TRACE("deref => %p\n", Pointer); - } switch (type) { case RPC_FC_RP: /* ref pointer (always non-null) */ break; case RPC_FC_OP: case RPC_FC_UP: - pStubMsg->BufferLength += 4; /* NULL pointer has no further representation */ if (!Pointer) return; break; case RPC_FC_FP: + pointer_needs_sizing = !NdrFullPointerQueryPointer( + pStubMsg->FullPtrXlatTables, Pointer, 0, &pointer_id); + if (!pointer_needs_sizing) + return; + break; default: FIXME("unhandled ptr type=%02x\n", type); RpcRaiseException(RPC_X_BAD_STUB_DATA); + return; + } + + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); } m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; @@ -853,9 +986,9 @@ void WINAPI PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, } /*********************************************************************** - * PointerMemorySize [RPCRT4.@] + * PointerMemorySize [internal] */ -unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned long PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *Buffer, PFORMAT_STRING pFormat) { @@ -864,13 +997,10 @@ unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, NDR_MEMORYSIZE m; FIXME("(%p,%p,%p): stub\n", pStubMsg, Buffer, pFormat); - TRACE("type=%d, attr=", type); dump_pointer_attr(attr); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); pFormat += 2; if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - TRACE("deref\n"); - } switch (type) { case RPC_FC_RP: /* ref pointer (always non-null) */ @@ -880,6 +1010,10 @@ unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, RpcRaiseException(RPC_X_BAD_STUB_DATA); } + if (attr & RPC_FC_P_DEREF) { + TRACE("deref\n"); + } + m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; if (m) m(pStubMsg, desc); else FIXME("no memorysizer for data type=%02x\n", *desc); @@ -888,9 +1022,9 @@ unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, } /*********************************************************************** - * PointerFree [RPCRT4.@] + * PointerFree [internal] */ -void WINAPI PointerFree(PMIDL_STUB_MESSAGE pStubMsg, +static void PointerFree(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *Pointer, PFORMAT_STRING pFormat) { @@ -899,18 +1033,26 @@ void WINAPI PointerFree(PMIDL_STUB_MESSAGE pStubMsg, NDR_FREE m; TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); - TRACE("type=%d, attr=", type); dump_pointer_attr(attr); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); if (attr & RPC_FC_P_DONTFREE) return; pFormat += 2; if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; else desc = pFormat + *(const SHORT*)pFormat; + + if (!Pointer) return; + + if (type == RPC_FC_FP) { + int pointer_needs_freeing = NdrFullPointerFree( + pStubMsg->FullPtrXlatTables, Pointer); + if (!pointer_needs_freeing) + return; + } + if (attr & RPC_FC_P_DEREF) { Pointer = *(unsigned char**)Pointer; TRACE("deref => %p\n", Pointer); } - if (!Pointer) return; - m = NdrFreer[*desc & NDR_TABLE_MASK]; if (m) m(pStubMsg, Pointer, desc); @@ -923,10 +1065,12 @@ void WINAPI PointerFree(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_BOGUS_STRUCT: case RPC_FC_BOGUS_ARRAY: case RPC_FC_USER_MARSHAL: + case RPC_FC_CARRAY: + case RPC_FC_CVARRAY: break; default: FIXME("unhandled data type=%02x\n", *desc); - case RPC_FC_CARRAY: + break; case RPC_FC_C_CSTRING: case RPC_FC_C_WSTRING: if (pStubMsg->ReuseBuffer) goto notfree; @@ -949,13 +1093,14 @@ notfree: /*********************************************************************** * EmbeddedPointerMarshall */ -unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned char * EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { unsigned char *Mark = pStubMsg->BufferMark; unsigned long Offset = pStubMsg->Offset; unsigned ofs, rep, count, stride, xofs; + unsigned i; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -983,7 +1128,7 @@ unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 10; break; case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; stride = *(const WORD*)&pFormat[2]; ofs = *(const WORD*)&pFormat[4]; count = *(const WORD*)&pFormat[6]; @@ -991,17 +1136,21 @@ unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 8; break; } - /* ofs doesn't seem to matter in this context */ - while (rep) { + for (i = 0; i < rep; i++) { PFORMAT_STRING info = pFormat; - unsigned char *membase = pMemory + xofs; + unsigned char *membase = pMemory + (i * stride); + unsigned char *bufbase = Mark + (i * stride); unsigned u; + /* ofs doesn't seem to matter in this context */ for (u=0; uMemory; + + pStubMsg->Memory = pMemory; PointerMarshall(pStubMsg, bufptr, *(unsigned char**)memptr, info+4); + pStubMsg->Memory = saved_memory; } - rep--; } pFormat += 8 * count; } @@ -1014,7 +1163,7 @@ unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * EmbeddedPointerUnmarshall */ -unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned char * EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc) @@ -1022,6 +1171,7 @@ unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *Mark = pStubMsg->BufferMark; unsigned long Offset = pStubMsg->Offset; unsigned ofs, rep, count, stride, xofs; + unsigned i; TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -1029,6 +1179,7 @@ unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 2; while (pFormat[0] != RPC_FC_END) { + TRACE("pFormat[0] = 0x%x\n", pFormat[0]); switch (pFormat[0]) { default: FIXME("unknown repeat type %d\n", pFormat[0]); @@ -1049,7 +1200,7 @@ unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 10; break; case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; stride = *(const WORD*)&pFormat[2]; ofs = *(const WORD*)&pFormat[4]; count = *(const WORD*)&pFormat[6]; @@ -1058,16 +1209,16 @@ unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, break; } /* ofs doesn't seem to matter in this context */ - while (rep) { + for (i = 0; i < rep; i++) { PFORMAT_STRING info = pFormat; - unsigned char *membase = *ppMemory + xofs; + unsigned char *membase = *ppMemory + (i * stride); + unsigned char *bufbase = Mark + (i * stride); unsigned u; for (u=0; uOffset; unsigned ofs, rep, count, stride, xofs; + unsigned i; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pStubMsg->IgnoreEmbeddedPointers) return; + if (*pFormat != RPC_FC_PP) return; pFormat += 2; @@ -1110,7 +1265,7 @@ void WINAPI EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 10; break; case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; stride = *(const WORD*)&pFormat[2]; ofs = *(const WORD*)&pFormat[4]; count = *(const WORD*)&pFormat[6]; @@ -1119,31 +1274,36 @@ void WINAPI EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, break; } /* ofs doesn't seem to matter in this context */ - while (rep) { + for (i = 0; i < rep; i++) { PFORMAT_STRING info = pFormat; - unsigned char *membase = pMemory + xofs; + unsigned char *membase = pMemory + (i * stride); unsigned u; for (u=0; uMemory; + + pStubMsg->Memory = pMemory; PointerBufferSize(pStubMsg, *(unsigned char**)memptr, info+4); + pStubMsg->Memory = saved_memory; } - rep--; } pFormat += 8 * count; } } /*********************************************************************** - * EmbeddedPointerMemorySize + * EmbeddedPointerMemorySize [internal] */ -unsigned long WINAPI EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned long EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { unsigned long Offset = pStubMsg->Offset; unsigned char *Mark = pStubMsg->BufferMark; unsigned ofs, rep, count, stride, xofs; + unsigned i; FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (*pFormat != RPC_FC_PP) return 0; pFormat += 2; @@ -1168,7 +1328,7 @@ unsigned long WINAPI EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 10; break; case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; stride = *(const WORD*)&pFormat[2]; ofs = *(const WORD*)&pFormat[4]; count = *(const WORD*)&pFormat[6]; @@ -1177,14 +1337,14 @@ unsigned long WINAPI EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, break; } /* ofs doesn't seem to matter in this context */ - while (rep) { + for (i = 0; i < rep; i++) { PFORMAT_STRING info = pFormat; + unsigned char *bufbase = Mark + (i * stride); unsigned u; for (u=0; uOffset; unsigned ofs, rep, count, stride, xofs; + unsigned i; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); if (*pFormat != RPC_FC_PP) return; @@ -1227,7 +1388,7 @@ void WINAPI EmbeddedPointerFree(PMIDL_STUB_MESSAGE pStubMsg, pFormat += 10; break; case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; stride = *(const WORD*)&pFormat[2]; ofs = *(const WORD*)&pFormat[4]; count = *(const WORD*)&pFormat[6]; @@ -1236,15 +1397,18 @@ void WINAPI EmbeddedPointerFree(PMIDL_STUB_MESSAGE pStubMsg, break; } /* ofs doesn't seem to matter in this context */ - while (rep) { + for (i = 0; i < rep; i++) { PFORMAT_STRING info = pFormat; - unsigned char *membase = pMemory + xofs; + unsigned char *membase = pMemory + (i * stride); unsigned u; for (u=0; uMemory; + + pStubMsg->Memory = pMemory; PointerFree(pStubMsg, *(unsigned char**)memptr, info+4); + pStubMsg->Memory = saved_memory; } - rep--; } pFormat += 8 * count; } @@ -1257,10 +1421,23 @@ unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { + unsigned char *Buffer; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - pStubMsg->BufferMark = pStubMsg->Buffer; - PointerMarshall(pStubMsg, pStubMsg->Buffer, pMemory, pFormat); + /* incremement the buffer here instead of in PointerMarshall, + * as that is used by embedded pointers which already handle the incrementing + * the buffer, and shouldn't write any additional pointer data to the wire */ + if (*pFormat != RPC_FC_RP) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + Buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; + } + else + Buffer = pStubMsg->Buffer; + + PointerMarshall(pStubMsg, Buffer, pMemory, pFormat); STD_OVERFLOW_CHECK(pStubMsg); @@ -1275,10 +1452,24 @@ unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { + unsigned char *Buffer; + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - pStubMsg->BufferMark = pStubMsg->Buffer; - PointerUnmarshall(pStubMsg, pStubMsg->Buffer, ppMemory, pFormat, fMustAlloc); + /* incremement the buffer here instead of in PointerUnmarshall, + * as that is used by embedded pointers which already handle the incrementing + * the buffer, and shouldn't read any additional pointer data from the + * buffer */ + if (*pFormat != RPC_FC_RP) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + Buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; + } + else + Buffer = pStubMsg->Buffer; + + PointerUnmarshall(pStubMsg, Buffer, ppMemory, pFormat, fMustAlloc); return NULL; } @@ -1291,14 +1482,24 @@ void WINAPI NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + /* incremement the buffer length here instead of in PointerBufferSize, + * as that is used by embedded pointers which already handle the buffer + * length, and shouldn't write anything more to the wire */ + if (*pFormat != RPC_FC_RP) + { + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 4; + } + PointerBufferSize(pStubMsg, pMemory, pFormat); } /*********************************************************************** * NdrPointerMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { /* unsigned size = *(LPWORD)(pFormat+2); */ FIXME("(%p,%p): stub\n", pStubMsg, pFormat); @@ -1317,6 +1518,24 @@ void WINAPI NdrPointerFree(PMIDL_STUB_MESSAGE pStubMsg, PointerFree(pStubMsg, pMemory, pFormat); } +/*********************************************************************** + * NdrSimpleTypeMarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, + unsigned char FormatChar ) +{ + NdrBaseTypeMarshall(pStubMsg, pMemory, &FormatChar); +} + +/*********************************************************************** + * NdrSimpleTypeUnmarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, + unsigned char FormatChar ) +{ + NdrBaseTypeUnmarshall(pStubMsg, &pMemory, &FormatChar, 0); +} + /*********************************************************************** * NdrSimpleStructMarshall [RPCRT4.@] */ @@ -1327,6 +1546,8 @@ unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned size = *(const WORD*)(pFormat+2); TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + memcpy(pStubMsg->Buffer, pMemory, size); pStubMsg->BufferMark = pStubMsg->Buffer; pStubMsg->Buffer += size; @@ -1334,15 +1555,7 @@ unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, if (pFormat[0] != RPC_FC_STRUCT) EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4); - /* - * This test does not work when NdrSimpleStructMarshall is called - * by an rpc-server to marshall data to return to the client because - * BufferStart and BufferEnd are bogus. MIDL does not update them - * when a new buffer is allocated in order to return data to the caller. - */ -#if 0 STD_OVERFLOW_CHECK(pStubMsg); -#endif return NULL; } @@ -1358,13 +1571,14 @@ unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned size = *(const WORD*)(pFormat+2); TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + if (fMustAlloc) { *ppMemory = NdrAllocate(pStubMsg, size); memcpy(*ppMemory, pStubMsg->Buffer, size); } else { - if (pStubMsg->ReuseBuffer && !*ppMemory) - /* for servers, we may just point straight into the RPC buffer, I think - * (I guess that's what MS does since MIDL code doesn't try to free) */ + if (!pStubMsg->IsClient && !*ppMemory) + /* for servers, we just point straight into the RPC buffer */ *ppMemory = pStubMsg->Buffer; else /* for clients, memory should be provided by caller */ @@ -1380,29 +1594,6 @@ unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, return NULL; } - -/*********************************************************************** - * NdrSimpleTypeUnmarshall [RPCRT4.@] - */ -void WINAPI NdrSimpleTypeMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - unsigned char FormatChar) -{ - FIXME("stub\n"); -} - - -/*********************************************************************** - * NdrSimpleTypeUnmarshall [RPCRT4.@] - */ -void WINAPI NdrSimpleTypeUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - unsigned char FormatChar) -{ - FIXME("stub\n"); -} - - /*********************************************************************** * NdrSimpleStructBufferSize [RPCRT4.@] */ @@ -1412,6 +1603,9 @@ void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, { unsigned size = *(const WORD*)(pFormat+2); TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1); + pStubMsg->BufferLength += size; if (pFormat[0] != RPC_FC_STRUCT) EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4); @@ -1420,14 +1614,20 @@ void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrSimpleStructMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { - /* unsigned size = *(LPWORD)(pFormat+2); */ - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + unsigned short size = *(const WORD *)(pFormat+2); + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + pStubMsg->MemorySize += size; + pStubMsg->Buffer += size; + if (pFormat[0] != RPC_FC_STRUCT) EmbeddedPointerMemorySize(pStubMsg, pFormat+4); - return 0; + return size; } /*********************************************************************** @@ -1443,7 +1643,7 @@ void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg, } -unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned long EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { switch (*pFormat) { @@ -1451,9 +1651,22 @@ unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_PSTRUCT: case RPC_FC_CSTRUCT: case RPC_FC_BOGUS_STRUCT: + case RPC_FC_SMFARRAY: + case RPC_FC_SMVARRAY: return *(const WORD*)&pFormat[2]; case RPC_FC_USER_MARSHAL: return *(const WORD*)&pFormat[4]; + case RPC_FC_NON_ENCAPSULATED_UNION: + pFormat += 2; + if (pStubMsg->fHasNewCorrDesc) + pFormat += 6; + else + pFormat += 4; + + pFormat += *(const SHORT*)pFormat; + return *(const SHORT*)pFormat; + case RPC_FC_IP: + return sizeof(void *); default: FIXME("unhandled embedded type %02x\n", *pFormat); } @@ -1461,7 +1674,22 @@ unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, } -unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned long EmbeddedComplexMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + NDR_MEMORYSIZE m = NdrMemorySizer[*pFormat & NDR_TABLE_MASK]; + + if (!m) + { + FIXME("no memorysizer for data type=%02x\n", *pFormat); + return 0; + } + + return m(pStubMsg, pFormat); +} + + +static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, PFORMAT_STRING pPointer) @@ -1472,6 +1700,16 @@ unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, while (*pFormat != RPC_FC_END) { switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + TRACE("byte=%d <= %p\n", *(WORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 1); + pStubMsg->Buffer += 1; + pMemory += 1; + break; + case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: TRACE("short=%d <= %p\n", *(WORD*)pMemory, pMemory); @@ -1482,11 +1720,17 @@ unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ENUM32: - TRACE("long=%ld <= %p\n", *(DWORD*)pMemory, pMemory); + TRACE("long=%d <= %p\n", *(DWORD*)pMemory, pMemory); memcpy(pStubMsg->Buffer, pMemory, 4); pStubMsg->Buffer += 4; pMemory += 4; break; + case RPC_FC_HYPER: + TRACE("longlong=%s <= %p\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory), pMemory); + memcpy(pStubMsg->Buffer, pMemory, 8); + pStubMsg->Buffer += 8; + pMemory += 8; + break; case RPC_FC_POINTER: TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory); NdrPointerMarshall(pStubMsg, *(unsigned char**)pMemory, pPointer); @@ -1494,13 +1738,19 @@ unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, pMemory += 4; break; case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); + ALIGN_POINTER(pMemory, 4); break; case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); + ALIGN_POINTER(pMemory, 8); break; + case RPC_FC_STRUCTPAD1: case RPC_FC_STRUCTPAD2: - pMemory += 2; + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; break; case RPC_FC_EMBEDDED_COMPLEX: pMemory += pFormat[1]; @@ -1517,7 +1767,7 @@ unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_PAD: break; default: - FIXME("unhandled format %02x\n", *pFormat); + FIXME("unhandled format 0x%02x\n", *pFormat); } pFormat++; } @@ -1525,11 +1775,10 @@ unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, return pMemory; } -unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, - PFORMAT_STRING pPointer, - unsigned char fMustAlloc) + PFORMAT_STRING pPointer) { PFORMAT_STRING desc; NDR_UNMARSHALL m; @@ -1537,6 +1786,16 @@ unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, while (*pFormat != RPC_FC_END) { switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + memcpy(pMemory, pStubMsg->Buffer, 1); + TRACE("byte=%d => %p\n", *(WORD*)pMemory, pMemory); + pStubMsg->Buffer += 1; + pMemory += 1; + break; + case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: memcpy(pMemory, pStubMsg->Buffer, 2); @@ -1548,25 +1807,36 @@ unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_ULONG: case RPC_FC_ENUM32: memcpy(pMemory, pStubMsg->Buffer, 4); - TRACE("long=%ld => %p\n", *(DWORD*)pMemory, pMemory); + TRACE("long=%d => %p\n", *(DWORD*)pMemory, pMemory); pStubMsg->Buffer += 4; pMemory += 4; break; + case RPC_FC_HYPER: + memcpy(pMemory, pStubMsg->Buffer, 8); + TRACE("longlong=%s => %p\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory), pMemory); + pStubMsg->Buffer += 8; + pMemory += 8; + break; case RPC_FC_POINTER: - *(unsigned char**)pMemory = NULL; TRACE("pointer => %p\n", pMemory); - NdrPointerUnmarshall(pStubMsg, (unsigned char**)pMemory, pPointer, fMustAlloc); + NdrPointerUnmarshall(pStubMsg, (unsigned char**)pMemory, pPointer, TRUE); pPointer += 4; pMemory += 4; break; case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); + ALIGN_POINTER(pMemory, 4); break; case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); + ALIGN_POINTER(pMemory, 8); break; + case RPC_FC_STRUCTPAD1: case RPC_FC_STRUCTPAD2: - pMemory += 2; + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; break; case RPC_FC_EMBEDDED_COMPLEX: pMemory += pFormat[1]; @@ -1576,7 +1846,7 @@ unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, TRACE("embedded complex (size=%ld) => %p\n", size, pMemory); m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; memset(pMemory, 0, size); /* just in case */ - if (m) m(pStubMsg, &pMemory, desc, fMustAlloc); + if (m) m(pStubMsg, &pMemory, desc, FALSE); else FIXME("no unmarshaller for embedded type %02x\n", *desc); pMemory += size; pFormat += 2; @@ -1592,7 +1862,7 @@ unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, return pMemory; } -unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, PFORMAT_STRING pPointer) @@ -1603,6 +1873,14 @@ unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, while (*pFormat != RPC_FC_END) { switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + pStubMsg->BufferLength += 1; + pMemory += 1; + break; + case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: pStubMsg->BufferLength += 2; @@ -1614,19 +1892,29 @@ unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, pStubMsg->BufferLength += 4; pMemory += 4; break; + case RPC_FC_HYPER: + pStubMsg->BufferLength += 8; + pMemory += 8; + break; case RPC_FC_POINTER: NdrPointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); pPointer += 4; pMemory += 4; break; case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); + ALIGN_POINTER(pMemory, 4); break; case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); + ALIGN_POINTER(pMemory, 8); break; + case RPC_FC_STRUCTPAD1: case RPC_FC_STRUCTPAD2: - pMemory += 2; + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; break; case RPC_FC_EMBEDDED_COMPLEX: pMemory += pFormat[1]; @@ -1642,7 +1930,7 @@ unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_PAD: break; default: - FIXME("unhandled format %d\n", *pFormat); + FIXME("unhandled format 0x%02x\n", *pFormat); } pFormat++; } @@ -1650,7 +1938,7 @@ unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, return pMemory; } -unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, PFORMAT_STRING pPointer) @@ -1661,6 +1949,13 @@ unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, while (*pFormat != RPC_FC_END) { switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + pMemory += 1; + break; + case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: pMemory += 2; @@ -1670,19 +1965,28 @@ unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_ENUM32: pMemory += 4; break; + case RPC_FC_HYPER: + pMemory += 8; + break; case RPC_FC_POINTER: NdrPointerFree(pStubMsg, *(unsigned char**)pMemory, pPointer); pPointer += 4; pMemory += 4; break; case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); + ALIGN_POINTER(pMemory, 4); break; case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); + ALIGN_POINTER(pMemory, 8); break; + case RPC_FC_STRUCTPAD1: case RPC_FC_STRUCTPAD2: - pMemory += 2; + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; break; case RPC_FC_EMBEDDED_COMPLEX: pMemory += pFormat[1]; @@ -1698,7 +2002,7 @@ unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, case RPC_FC_PAD: break; default: - FIXME("unhandled format %d\n", *pFormat); + FIXME("unhandled format 0x%02x\n", *pFormat); } pFormat++; } @@ -1706,7 +2010,7 @@ unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, return pMemory; } -unsigned long WINAPI ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, +static unsigned long ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { PFORMAT_STRING desc; @@ -1714,37 +2018,61 @@ unsigned long WINAPI ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, while (*pFormat != RPC_FC_END) { switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + size += 1; + pStubMsg->Buffer += 1; + break; + case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: size += 2; + pStubMsg->Buffer += 2; break; case RPC_FC_LONG: case RPC_FC_ULONG: + case RPC_FC_ENUM32: size += 4; + pStubMsg->Buffer += 4; + break; + case RPC_FC_HYPER: + size += 8; + pStubMsg->Buffer += 8; break; case RPC_FC_POINTER: size += 4; + pStubMsg->Buffer += 4; break; case RPC_FC_ALIGNM4: - ALIGN_LENGTH(size, 3); + ALIGN_LENGTH(size, 4); + ALIGN_POINTER(pStubMsg->Buffer, 4); break; case RPC_FC_ALIGNM8: - ALIGN_LENGTH(size, 7); + ALIGN_LENGTH(size, 8); + ALIGN_POINTER(pStubMsg->Buffer, 8); break; + case RPC_FC_STRUCTPAD1: case RPC_FC_STRUCTPAD2: - size += 2; + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + size += *pFormat - RPC_FC_STRUCTPAD1 + 1; break; case RPC_FC_EMBEDDED_COMPLEX: size += pFormat[1]; pFormat += 2; desc = pFormat + *(const SHORT*)pFormat; - size += EmbeddedComplexSize(pStubMsg, desc); + size += EmbeddedComplexMemorySize(pStubMsg, desc); pFormat += 2; continue; case RPC_FC_PAD: break; default: - FIXME("unhandled format %d\n", *pFormat); + FIXME("unhandled format 0x%02x\n", *pFormat); } pFormat++; } @@ -1765,6 +2093,8 @@ unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + pFormat += 4; if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; pFormat += 2; @@ -1800,6 +2130,8 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + if (fMustAlloc || !*ppMemory) { *ppMemory = NdrAllocate(pStubMsg, size); @@ -1812,7 +2144,7 @@ unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; pFormat += 2; - pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc, fMustAlloc); + pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc); if (conf_array) NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); @@ -1833,6 +2165,8 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1); + pFormat += 4; if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; pFormat += 2; @@ -1852,14 +2186,16 @@ void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrComplexStructMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { - /* unsigned size = *(LPWORD)(pFormat+2); */ + unsigned size = *(const WORD*)(pFormat+2); PFORMAT_STRING conf_array = NULL; PFORMAT_STRING pointer_desc = NULL; - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); pFormat += 4; if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; @@ -1867,7 +2203,12 @@ unsigned long WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; pFormat += 2; - return 0; + ComplexStructMemorySize(pStubMsg, pFormat); + + if (conf_array) + NdrConformantArrayMemorySize(pStubMsg, conf_array); + + return size; } /*********************************************************************** @@ -1907,18 +2248,21 @@ unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { DWORD size = 0, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - size = pStubMsg->MaxCount; - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); - pStubMsg->Buffer += 4; + WriteConformance(pStubMsg); - memcpy(pStubMsg->Buffer, pMemory, size*esize); + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + size = safe_multiply(esize, pStubMsg->MaxCount); + memcpy(pStubMsg->Buffer, pMemory, size); pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += size*esize; + pStubMsg->Buffer += size; EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); @@ -1935,20 +2279,25 @@ unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - DWORD size = 0, esize = *(const WORD*)(pFormat+2); + DWORD size, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); pFormat = ReadConformance(pStubMsg, pFormat+4); - size = pStubMsg->MaxCount; + + size = safe_multiply(esize, pStubMsg->MaxCount); if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, size*esize); + *ppMemory = NdrAllocate(pStubMsg, size); - memcpy(*ppMemory, pStubMsg->Buffer, size*esize); + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + memcpy(*ppMemory, pStubMsg->Buffer, size); pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += size*esize; + pStubMsg->Buffer += size; EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -1962,15 +2311,21 @@ void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - DWORD size = 0, esize = *(const WORD*)(pFormat+2); + DWORD size, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - size = pStubMsg->MaxCount; + SizeConformance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + size = safe_multiply(esize, pStubMsg->MaxCount); /* conformance value plus array */ - pStubMsg->BufferLength += sizeof(DWORD) + size*esize; + pStubMsg->BufferLength += size; EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); } @@ -1978,21 +2333,26 @@ void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrConformantArrayMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { DWORD size = 0, esize = *(const WORD*)(pFormat+2); - unsigned char *buffer; + unsigned char alignment = pFormat[1] + 1; TRACE("(%p,%p)\n", pStubMsg, pFormat); if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - buffer = pStubMsg->Buffer; pFormat = ReadConformance(pStubMsg, pFormat+4); - pStubMsg->Buffer = buffer; - size = pStubMsg->MaxCount; + size = safe_multiply(esize, pStubMsg->MaxCount); + pStubMsg->MemorySize += size; - return size*esize; + ALIGN_POINTER(pStubMsg->Buffer, alignment); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return pStubMsg->MemorySize; } /*********************************************************************** @@ -2005,6 +2365,8 @@ void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg, TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); } @@ -2016,6 +2378,8 @@ unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStu unsigned char* pMemory, PFORMAT_STRING pFormat ) { + ULONG bufsize; + unsigned char alignment = pFormat[1] + 1; DWORD esize = *(const WORD*)(pFormat+2); TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); @@ -2030,16 +2394,16 @@ unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStu pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->MaxCount); - pStubMsg->Buffer += 4; - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->Offset); - pStubMsg->Buffer += 4; - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->ActualCount); - pStubMsg->Buffer += 4; + WriteConformance(pStubMsg); + WriteVariance(pStubMsg); - memcpy(pStubMsg->Buffer, pMemory + pStubMsg->Offset, pStubMsg->ActualCount*esize); + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + memcpy(pStubMsg->Buffer, pMemory + pStubMsg->Offset, bufsize); pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += pStubMsg->ActualCount*esize; + pStubMsg->Buffer += bufsize; EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); @@ -2057,6 +2421,8 @@ unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pS PFORMAT_STRING pFormat, unsigned char fMustAlloc ) { + ULONG bufsize, memsize; + unsigned char alignment = pFormat[1] + 1; DWORD esize = *(const WORD*)(pFormat+2); TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -2067,13 +2433,19 @@ unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pS RpcRaiseException(RPC_S_INTERNAL_ERROR); return NULL; } - pFormat = ReadConformance(pStubMsg, pFormat); - pFormat = ReadVariance(pStubMsg, pFormat); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + memsize = safe_multiply(esize, pStubMsg->MaxCount); if (!*ppMemory || fMustAlloc) - *ppMemory = NdrAllocate(pStubMsg, pStubMsg->MaxCount * esize); - memcpy(*ppMemory + pStubMsg->Offset, pStubMsg->Buffer, pStubMsg->ActualCount * esize); - pStubMsg->Buffer += pStubMsg->ActualCount * esize; + *ppMemory = NdrAllocate(pStubMsg, memsize); + memcpy(*ppMemory + pStubMsg->Offset, pStubMsg->Buffer, bufsize); + pStubMsg->Buffer += bufsize; EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -2088,7 +2460,19 @@ void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat ) { - FIXME( "stub\n" ); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_CVARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); } @@ -2098,6 +2482,7 @@ void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg, void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, PFORMAT_STRING pFormat ) { + unsigned char alignment = pFormat[1] + 1; DWORD esize = *(const WORD*)(pFormat+2); TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); @@ -2114,8 +2499,12 @@ void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, /* compute length */ pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); - /* conformance + offset + variance + array */ - pStubMsg->BufferLength += 3*sizeof(DWORD) + pStubMsg->ActualCount*esize; + SizeConformance(pStubMsg); + SizeVariance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + pStubMsg->BufferLength += safe_multiply(esize, pStubMsg->ActualCount); EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); } @@ -2124,8 +2513,8 @@ void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrConformantVaryingArrayMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat ) +ULONG WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) { FIXME( "stub\n" ); return 0; @@ -2139,8 +2528,9 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - ULONG count, def; + ULONG i, count, def; BOOL variance_present; + unsigned char alignment; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2151,6 +2541,8 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, return NULL; } + alignment = pFormat[1] + 1; + def = *(const WORD*)&pFormat[2]; pFormat += 4; @@ -2159,19 +2551,16 @@ unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, variance_present = IsConformanceOrVariancePresent(pFormat); pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, pStubMsg->MaxCount); - TRACE("variance = %ld\n", pStubMsg->ActualCount); + TRACE("variance = %d\n", pStubMsg->ActualCount); - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->MaxCount); - pStubMsg->Buffer += 4; + WriteConformance(pStubMsg); if (variance_present) - { - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->Offset); - pStubMsg->Buffer += 4; - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->ActualCount); - pStubMsg->Buffer += 4; - } + WriteVariance(pStubMsg); - for (count = 0; count < pStubMsg->ActualCount; count++) + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) pMemory = ComplexMarshall(pStubMsg, pMemory, pFormat, NULL); STD_OVERFLOW_CHECK(pStubMsg); @@ -2187,8 +2576,10 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - ULONG count, esize; + ULONG i, count, esize, memsize; + unsigned char alignment; unsigned char *pMemory; + unsigned char *Buffer; TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); @@ -2199,22 +2590,32 @@ unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, return NULL; } + alignment = pFormat[1] + 1; + pFormat += 4; pFormat = ReadConformance(pStubMsg, pFormat); - pFormat = ReadVariance(pStubMsg, pFormat); + pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); - esize = ComplexStructSize(pStubMsg, pFormat); + Buffer = pStubMsg->Buffer; + pStubMsg->MemorySize = 0; + esize = ComplexStructMemorySize(pStubMsg, pFormat); + pStubMsg->Buffer = Buffer; + /* do multiply here instead of inside if block to verify MaxCount */ + memsize = safe_multiply(esize, pStubMsg->MaxCount); if (fMustAlloc || !*ppMemory) { - *ppMemory = NdrAllocate(pStubMsg, pStubMsg->MaxCount * esize); - memset(*ppMemory, 0, pStubMsg->MaxCount * esize); + *ppMemory = NdrAllocate(pStubMsg, memsize); + memset(*ppMemory, 0, memsize); } + ALIGN_POINTER(pStubMsg->Buffer, alignment); + pMemory = *ppMemory; - for (count = 0; count < pStubMsg->ActualCount; count++) - pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL, fMustAlloc); + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL); return NULL; } @@ -2226,7 +2627,8 @@ void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - ULONG count, def; + ULONG i, count, def; + unsigned char alignment; BOOL variance_present; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2238,32 +2640,40 @@ void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, return; } + alignment = pFormat[1] + 1; + def = *(const WORD*)&pFormat[2]; pFormat += 4; pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); TRACE("conformance = %ld\n", pStubMsg->MaxCount); - pStubMsg->BufferLength += sizeof(ULONG); + SizeConformance(pStubMsg); variance_present = IsConformanceOrVariancePresent(pFormat); pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, pStubMsg->MaxCount); - TRACE("variance = %ld\n", pStubMsg->ActualCount); + TRACE("variance = %d\n", pStubMsg->ActualCount); if (variance_present) - pStubMsg->BufferLength += 2*sizeof(ULONG); + SizeVariance(pStubMsg); - for (count=0; count < pStubMsg->ActualCount; count++) + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, NULL); } /*********************************************************************** * NdrComplexArrayMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { - DWORD size = 0; - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + ULONG i, count, esize, SavedMemorySize, MemorySize; + unsigned char alignment; + unsigned char *Buffer; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); if (pFormat[0] != RPC_FC_BOGUS_ARRAY) { @@ -2272,15 +2682,32 @@ unsigned long WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, return 0; } + alignment = pFormat[1] + 1; + pFormat += 4; pFormat = ReadConformance(pStubMsg, pFormat); - size = pStubMsg->MaxCount; - TRACE("conformance=%ld\n", size); + pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); - pFormat += 4; + ALIGN_POINTER(pStubMsg->Buffer, alignment); - return 0; + SavedMemorySize = pStubMsg->MemorySize; + + Buffer = pStubMsg->Buffer; + pStubMsg->MemorySize = 0; + esize = ComplexStructMemorySize(pStubMsg, pFormat); + pStubMsg->Buffer = Buffer; + + MemorySize = safe_multiply(pStubMsg->MaxCount, esize); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + ComplexStructMemorySize(pStubMsg, pFormat); + + pStubMsg->MemorySize = SavedMemorySize; + + pStubMsg->MemorySize += MemorySize; + return MemorySize; } /*********************************************************************** @@ -2290,7 +2717,7 @@ void WINAPI NdrComplexArrayFree(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - ULONG count, def; + ULONG i, count, def; TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); @@ -2308,18 +2735,23 @@ void WINAPI NdrComplexArrayFree(PMIDL_STUB_MESSAGE pStubMsg, TRACE("conformance = %ld\n", pStubMsg->MaxCount); pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, pStubMsg->MaxCount); - TRACE("variance = %ld\n", pStubMsg->ActualCount); + TRACE("variance = %d\n", pStubMsg->ActualCount); - for (count=0; count < pStubMsg->ActualCount; count++) + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) pMemory = ComplexFree(pStubMsg, pMemory, pFormat, NULL); } -unsigned long UserMarshalFlags(PMIDL_STUB_MESSAGE pStubMsg) +static ULONG UserMarshalFlags(PMIDL_STUB_MESSAGE pStubMsg) { return MAKELONG(pStubMsg->dwDestContext, pStubMsg->RpcMsg->DataRepresentation); } +#define USER_MARSHAL_PTR_PREFIX \ + ( (DWORD)'U' | ( (DWORD)'s' << 8 ) | \ + ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) ) + /*********************************************************************** * NdrUserMarshalMarshall [RPCRT4.@] */ @@ -2327,12 +2759,22 @@ unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { -/* unsigned flags = pFormat[1]; */ + unsigned flags = pFormat[1]; unsigned index = *(const WORD*)&pFormat[2]; - unsigned long uflag = UserMarshalFlags(pStubMsg); + ULONG uflag = UserMarshalFlags(pStubMsg); TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); TRACE("index=%d\n", index); + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, USER_MARSHAL_PTR_PREFIX); + pStubMsg->Buffer += 4; + ALIGN_POINTER(pStubMsg->Buffer, 8); + } + else + ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + pStubMsg->Buffer = pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnMarshall( &uflag, pStubMsg->Buffer, pMemory); @@ -2350,13 +2792,23 @@ unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { -/* unsigned flags = pFormat[1];*/ + unsigned flags = pFormat[1]; unsigned index = *(const WORD*)&pFormat[2]; DWORD memsize = *(const WORD*)&pFormat[4]; - unsigned long uflag = UserMarshalFlags(pStubMsg); + ULONG uflag = UserMarshalFlags(pStubMsg); TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); TRACE("index=%d\n", index); + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + /* skip pointer prefix */ + pStubMsg->Buffer += 4; + ALIGN_POINTER(pStubMsg->Buffer, 8); + } + else + ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + if (fMustAlloc || !*ppMemory) *ppMemory = NdrAllocate(pStubMsg, memsize); @@ -2374,15 +2826,25 @@ void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { -/* unsigned flags = pFormat[1];*/ + unsigned flags = pFormat[1]; unsigned index = *(const WORD*)&pFormat[2]; DWORD bufsize = *(const WORD*)&pFormat[6]; - unsigned long uflag = UserMarshalFlags(pStubMsg); + ULONG uflag = UserMarshalFlags(pStubMsg); TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); TRACE("index=%d\n", index); + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + /* skip pointer prefix */ + pStubMsg->BufferLength += 4; + ALIGN_LENGTH(pStubMsg->BufferLength, 8); + } + else + ALIGN_LENGTH(pStubMsg->BufferLength, (flags & 0xf) + 1); + if (bufsize) { - TRACE("size=%ld\n", bufsize); + TRACE("size=%d\n", bufsize); pStubMsg->BufferLength += bufsize; return; } @@ -2395,15 +2857,32 @@ void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrUserMarshalMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { + unsigned flags = pFormat[1]; unsigned index = *(const WORD*)&pFormat[2]; -/* DWORD memsize = *(const WORD*)&pFormat[4]; */ - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + DWORD memsize = *(const WORD*)&pFormat[4]; + DWORD bufsize = *(const WORD*)&pFormat[6]; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); TRACE("index=%d\n", index); - return 0; + pStubMsg->MemorySize += memsize; + + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + /* skip pointer prefix */ + pStubMsg->Buffer += 4; + ALIGN_POINTER(pStubMsg->Buffer, 8); + } + else + ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + + pStubMsg->Buffer += bufsize; + + return pStubMsg->MemorySize; } /*********************************************************************** @@ -2415,7 +2894,7 @@ void WINAPI NdrUserMarshalFree(PMIDL_STUB_MESSAGE pStubMsg, { /* unsigned flags = pFormat[1]; */ unsigned index = *(const WORD*)&pFormat[2]; - unsigned long uflag = UserMarshalFlags(pStubMsg); + ULONG uflag = UserMarshalFlags(pStubMsg); TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); TRACE("index=%d\n", index); @@ -2446,21 +2925,23 @@ void WINAPI NdrConvert( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) /*********************************************************************** * NdrConvert2 [RPCRT4.@] */ -void WINAPI NdrConvert2( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, long NumberParams ) +void WINAPI NdrConvert2( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, LONG NumberParams ) { - FIXME("(pStubMsg == ^%p, pFormat == ^%p, NumberParams == %ld): stub.\n", + FIXME("(pStubMsg == ^%p, pFormat == ^%p, NumberParams == %d): stub.\n", pStubMsg, pFormat, NumberParams); /* FIXME: since this stub doesn't do any converting, the proper behavior is to raise an exception */ } +#include "pshpack1.h" typedef struct _NDR_CSTRUCT_FORMAT { unsigned char type; unsigned char alignment; unsigned short memory_size; short offset_to_array_description; -} NDR_CSTRUCT_FORMAT; +} NDR_CSTRUCT_FORMAT, NDR_CVSTRUCT_FORMAT; +#include "poppack.h" /*********************************************************************** * NdrConformantStructMarshall [RPCRT4.@] @@ -2469,11 +2950,13 @@ unsigned char * WINAPI NdrConformantStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - const NDR_CSTRUCT_FORMAT * pCStructFormat = (NDR_CSTRUCT_FORMAT*)pFormat; - pFormat += sizeof(NDR_CSTRUCT_FORMAT); + const NDR_CSTRUCT_FORMAT *pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCArrayFormat; + ULONG esize, bufsize; TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat += sizeof(NDR_CSTRUCT_FORMAT); if ((pCStructFormat->type != RPC_FC_CPSTRUCT) && (pCStructFormat->type != RPC_FC_CSTRUCT)) { ERR("invalid format type %x\n", pCStructFormat->type); @@ -2481,20 +2964,36 @@ unsigned char * WINAPI NdrConformantStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, return NULL; } + pCArrayFormat = (const unsigned char *)&pCStructFormat->offset_to_array_description + + pCStructFormat->offset_to_array_description; + if (*pCArrayFormat != RPC_FC_CARRAY) + { + ERR("invalid array format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + esize = *(const WORD*)(pCArrayFormat+2); + + ComputeConformance(pStubMsg, pMemory + pCStructFormat->memory_size, + pCArrayFormat + 4, 0); + + WriteConformance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, pCStructFormat->alignment + 1); + TRACE("memory_size = %d\n", pCStructFormat->memory_size); + bufsize = safe_multiply(esize, pStubMsg->MaxCount); /* copy constant sized part of struct */ - memcpy(pStubMsg->Buffer, pMemory, pCStructFormat->memory_size); - pStubMsg->Buffer += pCStructFormat->memory_size; + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(pStubMsg->Buffer, pMemory, pCStructFormat->memory_size + bufsize); + pStubMsg->Buffer += pCStructFormat->memory_size + bufsize; - if (pCStructFormat->offset_to_array_description) - { - PFORMAT_STRING pArrayFormat = (unsigned char*)&pCStructFormat->offset_to_array_description + - pCStructFormat->offset_to_array_description; - NdrConformantArrayMarshall(pStubMsg, pMemory + pCStructFormat->memory_size, pArrayFormat); - } if (pCStructFormat->type == RPC_FC_CPSTRUCT) EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + return NULL; } @@ -2506,52 +3005,51 @@ unsigned char * WINAPI NdrConformantStructUnmarshall(PMIDL_STUB_MESSAGE pStubMs PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - const NDR_CSTRUCT_FORMAT * pCStructFormat = (NDR_CSTRUCT_FORMAT*)pFormat; - pFormat += sizeof(NDR_CSTRUCT_FORMAT); + const NDR_CSTRUCT_FORMAT *pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCArrayFormat; + ULONG esize, bufsize; TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + pFormat += sizeof(NDR_CSTRUCT_FORMAT); if ((pCStructFormat->type != RPC_FC_CPSTRUCT) && (pCStructFormat->type != RPC_FC_CSTRUCT)) { ERR("invalid format type %x\n", pCStructFormat->type); RpcRaiseException(RPC_S_INTERNAL_ERROR); return NULL; } + pCArrayFormat = (const unsigned char *)&pCStructFormat->offset_to_array_description + + pCStructFormat->offset_to_array_description; + if (*pCArrayFormat != RPC_FC_CARRAY) + { + ERR("invalid array format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + esize = *(const WORD*)(pCArrayFormat+2); + + pCArrayFormat = ReadConformance(pStubMsg, pCArrayFormat + 4); + + ALIGN_POINTER(pStubMsg->Buffer, pCStructFormat->alignment + 1); TRACE("memory_size = %d\n", pCStructFormat->memory_size); + bufsize = safe_multiply(esize, pStubMsg->MaxCount); /* work out how much memory to allocate if we need to do so */ if (!*ppMemory || fMustAlloc) { - SIZE_T size = pCStructFormat->memory_size; - - if (pCStructFormat->offset_to_array_description) - { - unsigned char *buffer; - PFORMAT_STRING pArrayFormat = (unsigned char*)&pCStructFormat->offset_to_array_description + - pCStructFormat->offset_to_array_description; - buffer = pStubMsg->Buffer; - pStubMsg->Buffer += pCStructFormat->memory_size; - size += NdrConformantArrayMemorySize(pStubMsg, pArrayFormat); - pStubMsg->Buffer = buffer; - } + SIZE_T size = pCStructFormat->memory_size + bufsize; *ppMemory = NdrAllocate(pStubMsg, size); } /* now copy the data */ - memcpy(*ppMemory, pStubMsg->Buffer, pCStructFormat->memory_size); - pStubMsg->Buffer += pCStructFormat->memory_size; - if (pCStructFormat->offset_to_array_description) - { - PFORMAT_STRING pArrayFormat = (unsigned char*)&pCStructFormat->offset_to_array_description + - pCStructFormat->offset_to_array_description; - unsigned char *pMemoryArray = *ppMemory + pCStructFormat->memory_size; - /* note that we pass fMustAlloc as 0 as we have already allocated the - * memory */ - NdrConformantArrayUnmarshall(pStubMsg, &pMemoryArray, pArrayFormat, 0); - } + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(*ppMemory, pStubMsg->Buffer, pCStructFormat->memory_size + bufsize); + pStubMsg->Buffer += pCStructFormat->memory_size + bufsize; + if (pCStructFormat->type == RPC_FC_CPSTRUCT) EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + return NULL; } @@ -2562,28 +3060,39 @@ void WINAPI NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - const NDR_CSTRUCT_FORMAT * pCStructFormat = (NDR_CSTRUCT_FORMAT*)pFormat; - pFormat += sizeof(NDR_CSTRUCT_FORMAT); + const NDR_CSTRUCT_FORMAT * pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCArrayFormat; + ULONG esize; + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat += sizeof(NDR_CSTRUCT_FORMAT); if ((pCStructFormat->type != RPC_FC_CPSTRUCT) && (pCStructFormat->type != RPC_FC_CSTRUCT)) { ERR("invalid format type %x\n", pCStructFormat->type); RpcRaiseException(RPC_S_INTERNAL_ERROR); return; } + pCArrayFormat = (const unsigned char *)&pCStructFormat->offset_to_array_description + + pCStructFormat->offset_to_array_description; + if (*pCArrayFormat != RPC_FC_CARRAY) + { + ERR("invalid array format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + esize = *(const WORD*)(pCArrayFormat+2); + + pCArrayFormat = ComputeConformance(pStubMsg, pMemory + pCStructFormat->memory_size, pCArrayFormat+4, 0); + SizeConformance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, pCStructFormat->alignment + 1); TRACE("memory_size = %d\n", pCStructFormat->memory_size); - /* add constant sized part of struct to buffer size */ - pStubMsg->BufferLength += pCStructFormat->memory_size; + pStubMsg->BufferLength += pCStructFormat->memory_size + + safe_multiply(pStubMsg->MaxCount, esize); - if (pCStructFormat->offset_to_array_description) - { - PFORMAT_STRING pArrayFormat = (unsigned char*)&pCStructFormat->offset_to_array_description + - pCStructFormat->offset_to_array_description; - NdrConformantArrayBufferSize(pStubMsg, pMemory + pCStructFormat->memory_size, pArrayFormat); - } if (pCStructFormat->type == RPC_FC_CPSTRUCT) EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); } @@ -2591,7 +3100,7 @@ void WINAPI NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrConformantStructMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrConformantStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrConformantStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { FIXME("stub\n"); @@ -2615,7 +3124,81 @@ unsigned char * WINAPI NdrConformantVaryingStructMarshall(PMIDL_STUB_MESSAGE pS unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize, bufsize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + switch (*pCVArrayFormat) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 4, 0); + pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat, 0); + break; + case RPC_FC_C_CSTRING: + TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + case RPC_FC_C_WSTRING: + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + WriteConformance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + /* write constant sized part */ + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(pStubMsg->Buffer, pMemory, pCVStructFormat->memory_size); + pStubMsg->Buffer += pCVStructFormat->memory_size; + + WriteVariance(pStubMsg); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + /* write array part */ + memcpy(pStubMsg->Buffer, pMemory + pCVStructFormat->memory_size, bufsize); + pStubMsg->Buffer += bufsize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + return NULL; } @@ -2627,7 +3210,103 @@ unsigned char * WINAPI NdrConformantVaryingStructUnmarshall(PMIDL_STUB_MESSAGE PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - FIXME("stub\n"); + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize, bufsize; + unsigned char cvarray_type; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + cvarray_type = *pCVArrayFormat; + switch (cvarray_type) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 4); + break; + case RPC_FC_C_CSTRING: + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + case RPC_FC_C_WSTRING: + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + /* work out how much memory to allocate if we need to do so */ + if (!*ppMemory || fMustAlloc) + { + SIZE_T size = pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->MaxCount); + *ppMemory = NdrAllocate(pStubMsg, size); + } + + /* copy the constant data */ + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(*ppMemory, pStubMsg->Buffer, pCVStructFormat->memory_size); + pStubMsg->Buffer += pCVStructFormat->memory_size; + + pCVArrayFormat = ReadVariance(pStubMsg, pCVArrayFormat, pStubMsg->MaxCount); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + if ((cvarray_type == RPC_FC_C_CSTRING) || + (cvarray_type == RPC_FC_C_WSTRING)) + { + ULONG i; + /* strings must always have null terminating bytes */ + if (bufsize < esize) + { + ERR("invalid string length of %d\n", pStubMsg->ActualCount); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + for (i = bufsize - esize; i < bufsize; i++) + if (pStubMsg->Buffer[i] != 0) + { + ERR("string not null-terminated at byte position %d, data is 0x%x\n", + i, pStubMsg->Buffer[i]); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + } + + /* copy the array data */ + memcpy(*ppMemory + pCVStructFormat->memory_size, pStubMsg->Buffer, + bufsize); + pStubMsg->Buffer += bufsize; + + if (cvarray_type == RPC_FC_C_CSTRING) + TRACE("string=%s\n", debugstr_a((char *)(*ppMemory + pCVStructFormat->memory_size))); + else if (cvarray_type == RPC_FC_C_WSTRING) + TRACE("string=%s\n", debugstr_w((WCHAR *)(*ppMemory + pCVStructFormat->memory_size))); + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + return NULL; } @@ -2638,17 +3317,134 @@ void WINAPI NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + switch (*pCVArrayFormat) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 4, 0); + pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat, 0); + break; + case RPC_FC_C_CSTRING: + TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + case RPC_FC_C_WSTRING: + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + SizeConformance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + pStubMsg->BufferLength += pCVStructFormat->memory_size; + SizeVariance(pStubMsg); + pStubMsg->BufferLength += safe_multiply(pStubMsg->MaxCount, esize); + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); } /*********************************************************************** * NdrConformantVaryingStructMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrConformantVaryingStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrConformantVaryingStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { - FIXME("stub\n"); - return 0; + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize; + unsigned char cvarray_type; + + TRACE("(%p, %p)\n", pStubMsg, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + cvarray_type = *pCVArrayFormat; + switch (cvarray_type) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 4); + break; + case RPC_FC_C_CSTRING: + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + case RPC_FC_C_WSTRING: + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + pStubMsg->Buffer += pCVStructFormat->memory_size; + pCVArrayFormat = ReadVariance(pStubMsg, pCVArrayFormat, pStubMsg->MaxCount); + pStubMsg->Buffer += pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->ActualCount); + + pStubMsg->MemorySize += pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->MaxCount); + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return pCVStructFormat->memory_size + pStubMsg->MaxCount * esize; } /*********************************************************************** @@ -2658,9 +3454,79 @@ void WINAPI NdrConformantVaryingStructFree(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + switch (*pCVArrayFormat) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 4, 0); + pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat, 0); + break; + case RPC_FC_C_CSTRING: + TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + case RPC_FC_C_WSTRING: + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); } +#include "pshpack1.h" +typedef struct +{ + unsigned char type; + unsigned char alignment; + unsigned short total_size; +} NDR_SMFARRAY_FORMAT; + +typedef struct +{ + unsigned char type; + unsigned char alignment; + unsigned long total_size; +} NDR_LGFARRAY_FORMAT; +#include "poppack.h" + /*********************************************************************** * NdrFixedArrayMarshall [RPCRT4.@] */ @@ -2668,7 +3534,39 @@ unsigned char * WINAPI NdrFixedArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + unsigned long total_size; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + ALIGN_POINTER(pStubMsg->Buffer, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + + memcpy(pStubMsg->Buffer, pMemory, total_size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += total_size; + + pFormat = EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + return NULL; } @@ -2680,7 +3578,41 @@ unsigned char * WINAPI NdrFixedArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - FIXME("stub\n"); + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + unsigned long total_size; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + ALIGN_POINTER(pStubMsg->Buffer, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, total_size); + memcpy(*ppMemory, pStubMsg->Buffer, total_size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += total_size; + + pFormat = EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + return NULL; } @@ -2691,17 +3623,76 @@ void WINAPI NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + unsigned long total_size; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + ALIGN_LENGTH(pStubMsg->BufferLength, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + pStubMsg->BufferLength += total_size; + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); } /*********************************************************************** * NdrFixedArrayMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrFixedArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrFixedArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { - FIXME("stub\n"); - return 0; + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + ULONG total_size; + + TRACE("(%p, %p)\n", pStubMsg, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + ALIGN_POINTER(pStubMsg->Buffer, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += total_size; + pStubMsg->MemorySize += total_size; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return total_size; } /*********************************************************************** @@ -2711,7 +3702,27 @@ void WINAPI NdrFixedArrayFree(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); } /*********************************************************************** @@ -2721,7 +3732,61 @@ unsigned char * WINAPI NdrVaryingArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + unsigned char alignment; + DWORD elements, esize; + ULONG bufsize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + if ((pStubMsg->ActualCount > elements) || + (pStubMsg->ActualCount + pStubMsg->Offset > elements)) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + + WriteVariance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + memcpy(pStubMsg->Buffer, pMemory + pStubMsg->Offset, bufsize); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += bufsize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + return NULL; } @@ -2733,7 +3798,55 @@ unsigned char * WINAPI NdrVaryingArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - FIXME("stub\n"); + unsigned char alignment; + DWORD size, elements, esize; + ULONG bufsize; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + size = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + size = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ReadVariance(pStubMsg, pFormat, elements); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + if (!*ppMemory || fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, size); + memcpy(*ppMemory + pStubMsg->Offset, pStubMsg->Buffer, bufsize); + pStubMsg->Buffer += bufsize; + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + return NULL; } @@ -2744,17 +3857,107 @@ void WINAPI NdrVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + unsigned char alignment; + DWORD elements, esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + if ((pStubMsg->ActualCount > elements) || + (pStubMsg->ActualCount + pStubMsg->Offset > elements)) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return; + } + + SizeVariance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + pStubMsg->BufferLength += safe_multiply(esize, pStubMsg->ActualCount); + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); } /*********************************************************************** * NdrVaryingArrayMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrVaryingArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrVaryingArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { - FIXME("stub\n"); - return 0; + unsigned char alignment; + DWORD size, elements, esize; + + TRACE("(%p, %p)\n", pStubMsg, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + size = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + size = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ReadVariance(pStubMsg, pFormat, elements); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + pStubMsg->Buffer += safe_multiply(esize, pStubMsg->ActualCount); + pStubMsg->MemorySize += size; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return pStubMsg->MemorySize; } /*********************************************************************** @@ -2764,7 +3967,47 @@ void WINAPI NdrVaryingArrayFree(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + unsigned char alignment; + DWORD elements; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + pFormat += sizeof(WORD); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + if ((pStubMsg->ActualCount > elements) || + (pStubMsg->ActualCount + pStubMsg->Offset > elements)) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return; + } + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); } /*********************************************************************** @@ -2803,7 +4046,7 @@ void WINAPI NdrEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrEncapsulatedUnionMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { FIXME("stub\n"); @@ -2820,6 +4063,53 @@ void WINAPI NdrEncapsulatedUnionFree(PMIDL_STUB_MESSAGE pStubMsg, FIXME("stub\n"); } +static PFORMAT_STRING get_arm_offset_from_union_arm_selector(PMIDL_STUB_MESSAGE pStubMsg, + unsigned long discriminant, + PFORMAT_STRING pFormat) +{ + unsigned short num_arms, arm, type; + + num_arms = *(const SHORT*)pFormat & 0x0fff; + pFormat += 2; + for(arm = 0; arm < num_arms; arm++) + { + if(discriminant == *(const ULONG*)pFormat) + { + pFormat += 4; + break; + } + pFormat += 6; + } + + type = *(const unsigned short*)pFormat; + TRACE("type %04x\n", type); + if(arm == num_arms) /* default arm extras */ + { + if(type == 0xffff) + { + ERR("no arm for 0x%lx and no default case\n", discriminant); + RpcRaiseException(RPC_S_INVALID_TAG); + return NULL; + } + if(type == 0) + { + TRACE("falling back to empty default case for 0x%lx\n", discriminant); + return NULL; + } + } + return pFormat; +} + +static PFORMAT_STRING get_non_encapsulated_union_arm(PMIDL_STUB_MESSAGE pStubMsg, + ULONG value, + PFORMAT_STRING pFormat) +{ + pFormat += *(const SHORT*)pFormat; + pFormat += 2; + + return get_arm_offset_from_union_arm_selector(pStubMsg, value, pFormat); +} + /*********************************************************************** * NdrNonEncapsulatedUnionMarshall [RPCRT4.@] */ @@ -2827,11 +4117,96 @@ unsigned char * WINAPI NdrNonEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE pStub unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + unsigned short type; + unsigned char switch_type; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat; + pFormat++; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, 0); + TRACE("got switch value 0x%lx\n", pStubMsg->MaxCount); + /* Marshall discriminant */ + NdrBaseTypeMarshall(pStubMsg, (unsigned char *)&pStubMsg->MaxCount, &switch_type); + + pFormat = get_non_encapsulated_union_arm(pStubMsg, pStubMsg->MaxCount, pFormat); + if(!pFormat) + return NULL; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + unsigned char basetype = LOBYTE(type); + return NdrBaseTypeMarshall(pStubMsg, pMemory, &basetype); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_MARSHALL m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) + { + unsigned char *saved_buffer = NULL; + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; /* for pointer ID */ + PointerMarshall(pStubMsg, saved_buffer, *(unsigned char **)pMemory, desc); + break; + default: + m(pStubMsg, pMemory, desc); + } + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + } return NULL; } -/*********************************************************************** +static long unmarshall_discriminant(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING *ppFormat) +{ + long discriminant = 0; + + switch(**ppFormat) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + discriminant = *(UCHAR *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(UCHAR); + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); + discriminant = *(USHORT *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(USHORT); + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG)); + discriminant = *(ULONG *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(ULONG); + break; + default: + FIXME("Unhandled base type: 0x%02x\n", **ppFormat); + } + (*ppFormat)++; + + if (pStubMsg->fHasNewCorrDesc) + *ppFormat += 6; + else + *ppFormat += 4; + return discriminant; +} + +/********************************************************************** * NdrNonEncapsulatedUnionUnmarshall [RPCRT4.@] */ unsigned char * WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, @@ -2839,7 +4214,58 @@ unsigned char * WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pSt PFORMAT_STRING pFormat, unsigned char fMustAlloc) { - FIXME("stub\n"); + long discriminant; + unsigned short type, size; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + pFormat++; + + /* Unmarshall discriminant */ + discriminant = unmarshall_discriminant(pStubMsg, &pFormat); + TRACE("unmarshalled discriminant %lx\n", discriminant); + + pFormat += *(const SHORT*)pFormat; + + size = *(const unsigned short*)pFormat; + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return NULL; + + if(!*ppMemory || fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, size); + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + unsigned char basetype = LOBYTE(type); + return NdrBaseTypeUnmarshall(pStubMsg, ppMemory, &basetype, fMustAlloc); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_UNMARSHALL m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + if (m) + { + unsigned char *saved_buffer = NULL; + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; /* for pointer ID */ + PointerUnmarshall(pStubMsg, saved_buffer, *(unsigned char ***)ppMemory, desc, TRUE); + break; + default: + m(pStubMsg, ppMemory, desc, fMustAlloc); + } + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + } return NULL; } @@ -2850,17 +4276,114 @@ void WINAPI NdrNonEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) { - FIXME("stub\n"); + unsigned short type; + unsigned char switch_type; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat; + pFormat++; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, 0); + TRACE("got switch value 0x%lx\n", pStubMsg->MaxCount); + /* Add discriminant size */ + NdrBaseTypeBufferSize(pStubMsg, (unsigned char *)&pStubMsg->MaxCount, &switch_type); + + pFormat = get_non_encapsulated_union_arm(pStubMsg, pStubMsg->MaxCount, pFormat); + if(!pFormat) + return; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + unsigned char basetype = LOBYTE(type); + NdrBaseTypeBufferSize(pStubMsg, pMemory, &basetype); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_BUFFERSIZE m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) + { + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 4; /* for pointer ID */ + PointerBufferSize(pStubMsg, *(unsigned char **)pMemory, desc); + break; + default: + m(pStubMsg, pMemory, desc); + } + } + else FIXME("no buffersizer for embedded type %02x\n", *desc); + } + return; } /*********************************************************************** * NdrNonEncapsulatedUnionMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrNonEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrNonEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { - FIXME("stub\n"); - return 0; + ULONG discriminant; + unsigned short type, size; + + pFormat++; + /* Unmarshall discriminant */ + discriminant = unmarshall_discriminant(pStubMsg, &pFormat); + TRACE("unmarshalled discriminant 0x%x\n", discriminant); + + pFormat += *(const SHORT*)pFormat; + + size = *(const unsigned short*)pFormat; + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return 0; + + pStubMsg->Memory += size; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + return NdrBaseTypeMemorySize(pStubMsg, pFormat); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_MEMORYSIZE m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; + unsigned char *saved_buffer; + if (m) + { + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; + ALIGN_LENGTH(pStubMsg->MemorySize, 4); + pStubMsg->MemorySize += 4; + PointerMemorySize(pStubMsg, saved_buffer, pFormat); + break; + default: + return m(pStubMsg, desc); + } + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + } + + TRACE("size %d\n", size); + return size; } /*********************************************************************** @@ -2909,7 +4432,7 @@ void WINAPI NdrByteCountPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrByteCountPointerMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrByteCountPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrByteCountPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { FIXME("stub\n"); @@ -2962,7 +4485,7 @@ void WINAPI NdrXmitOrRepAsBufferSize(PMIDL_STUB_MESSAGE pStubMsg, /*********************************************************************** * NdrXmitOrRepAsMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrXmitOrRepAsMemorySize(PMIDL_STUB_MESSAGE pStubMsg, +ULONG WINAPI NdrXmitOrRepAsMemorySize(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { FIXME("stub\n"); @@ -3002,7 +4525,7 @@ static unsigned char *WINAPI NdrBaseTypeMarshall( case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); *(USHORT *)pStubMsg->Buffer = *(USHORT *)pMemory; pStubMsg->Buffer += sizeof(USHORT); TRACE("value: 0x%04x\n", *(USHORT *)pMemory); @@ -3011,23 +4534,23 @@ static unsigned char *WINAPI NdrBaseTypeMarshall( case RPC_FC_ULONG: case RPC_FC_ERROR_STATUS_T: case RPC_FC_ENUM32: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG)); *(ULONG *)pStubMsg->Buffer = *(ULONG *)pMemory; pStubMsg->Buffer += sizeof(ULONG); - TRACE("value: 0x%08lx\n", *(ULONG *)pMemory); + TRACE("value: 0x%08x\n", *(ULONG *)pMemory); break; case RPC_FC_FLOAT: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(float) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(float)); *(float *)pStubMsg->Buffer = *(float *)pMemory; pStubMsg->Buffer += sizeof(float); break; case RPC_FC_DOUBLE: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(double) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(double)); *(double *)pStubMsg->Buffer = *(double *)pMemory; pStubMsg->Buffer += sizeof(double); break; case RPC_FC_HYPER: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONGLONG) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONGLONG)); *(ULONGLONG *)pStubMsg->Buffer = *(ULONGLONG *)pMemory; pStubMsg->Buffer += sizeof(ULONGLONG); TRACE("value: %s\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory)); @@ -3036,7 +4559,7 @@ static unsigned char *WINAPI NdrBaseTypeMarshall( /* only 16-bits on the wire, so do a sanity check */ if (*(UINT *)pMemory > USHRT_MAX) RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); - ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); *(USHORT *)pStubMsg->Buffer = *(UINT *)pMemory; pStubMsg->Buffer += sizeof(USHORT); TRACE("value: 0x%04x\n", *(UINT *)pMemory); @@ -3062,10 +4585,13 @@ static unsigned char *WINAPI NdrBaseTypeUnmarshall( { TRACE("pStubMsg: %p, ppMemory: %p, type: 0x%02x, fMustAlloc: %s\n", pStubMsg, ppMemory, *pFormat, fMustAlloc ? "true" : "false"); - if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, NdrBaseTypeMemorySize(pStubMsg, pFormat)); - - TRACE("*ppMemory: %p\n", *ppMemory); +#define BASE_TYPE_UNMARSHALL(type) \ + ALIGN_POINTER(pStubMsg->Buffer, sizeof(type)); \ + if (fMustAlloc || !*ppMemory) \ + *ppMemory = NdrAllocate(pStubMsg, sizeof(type)); \ + TRACE("*ppMemory: %p\n", *ppMemory); \ + **(type **)ppMemory = *(type *)pStubMsg->Buffer; \ + pStubMsg->Buffer += sizeof(type); switch(*pFormat) { @@ -3073,47 +4599,39 @@ static unsigned char *WINAPI NdrBaseTypeUnmarshall( case RPC_FC_CHAR: case RPC_FC_SMALL: case RPC_FC_USMALL: - **(UCHAR **)ppMemory = *(UCHAR *)pStubMsg->Buffer; - pStubMsg->Buffer += sizeof(UCHAR); + BASE_TYPE_UNMARSHALL(UCHAR); TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory); break; case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT) - 1); - **(USHORT **)ppMemory = *(USHORT *)pStubMsg->Buffer; - pStubMsg->Buffer += sizeof(USHORT); + BASE_TYPE_UNMARSHALL(USHORT); TRACE("value: 0x%04x\n", **(USHORT **)ppMemory); break; case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ERROR_STATUS_T: case RPC_FC_ENUM32: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG) - 1); - **(ULONG **)ppMemory = *(ULONG *)pStubMsg->Buffer; - pStubMsg->Buffer += sizeof(ULONG); - TRACE("value: 0x%08lx\n", **(ULONG **)ppMemory); + BASE_TYPE_UNMARSHALL(ULONG); + TRACE("value: 0x%08x\n", **(ULONG **)ppMemory); break; case RPC_FC_FLOAT: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(float) - 1); - **(float **)ppMemory = *(float *)pStubMsg->Buffer; - pStubMsg->Buffer += sizeof(float); + BASE_TYPE_UNMARSHALL(float); TRACE("value: %f\n", **(float **)ppMemory); break; case RPC_FC_DOUBLE: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(double) - 1); - **(double **)ppMemory = *(double*)pStubMsg->Buffer; - pStubMsg->Buffer += sizeof(double); + BASE_TYPE_UNMARSHALL(double); TRACE("value: %f\n", **(double **)ppMemory); break; case RPC_FC_HYPER: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONGLONG) - 1); - **(ULONGLONG **)ppMemory = *(ULONGLONG *)pStubMsg->Buffer; - pStubMsg->Buffer += sizeof(ULONGLONG); + BASE_TYPE_UNMARSHALL(ULONGLONG); TRACE("value: %s\n", wine_dbgstr_longlong(**(ULONGLONG **)ppMemory)); break; case RPC_FC_ENUM16: - ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT) - 1); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, sizeof(UINT)); + TRACE("*ppMemory: %p\n", *ppMemory); /* 16-bits on the wire, but int in memory */ **(UINT **)ppMemory = *(USHORT *)pStubMsg->Buffer; pStubMsg->Buffer += sizeof(USHORT); @@ -3122,6 +4640,7 @@ static unsigned char *WINAPI NdrBaseTypeUnmarshall( default: FIXME("Unhandled base type: 0x%02x\n", *pFormat); } +#undef BASE_TYPE_UNMARSHALL /* FIXME: what is the correct return value? */ @@ -3150,29 +4669,29 @@ static void WINAPI NdrBaseTypeBufferSize( case RPC_FC_SHORT: case RPC_FC_USHORT: case RPC_FC_ENUM16: - ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(USHORT) - 1); + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(USHORT)); pStubMsg->BufferLength += sizeof(USHORT); break; case RPC_FC_LONG: case RPC_FC_ULONG: case RPC_FC_ENUM32: - ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(ULONG) - 1); + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(ULONG)); pStubMsg->BufferLength += sizeof(ULONG); break; case RPC_FC_FLOAT: - ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(float) - 1); + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(float)); pStubMsg->BufferLength += sizeof(float); break; case RPC_FC_DOUBLE: - ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(double) - 1); + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(double)); pStubMsg->BufferLength += sizeof(double); break; case RPC_FC_HYPER: - ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(ULONGLONG) - 1); + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(ULONGLONG)); pStubMsg->BufferLength += sizeof(ULONGLONG); break; case RPC_FC_ERROR_STATUS_T: - ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(error_status_t) - 1); + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(error_status_t)); pStubMsg->BufferLength += sizeof(error_status_t); break; default: @@ -3183,7 +4702,7 @@ static void WINAPI NdrBaseTypeBufferSize( /*********************************************************************** * NdrBaseTypeMemorySize [internal] */ -static unsigned long WINAPI NdrBaseTypeMemorySize( +static ULONG WINAPI NdrBaseTypeMemorySize( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { @@ -3193,24 +4712,40 @@ static unsigned long WINAPI NdrBaseTypeMemorySize( case RPC_FC_CHAR: case RPC_FC_SMALL: case RPC_FC_USMALL: + pStubMsg->Buffer += sizeof(UCHAR); + pStubMsg->MemorySize += sizeof(UCHAR); return sizeof(UCHAR); case RPC_FC_WCHAR: case RPC_FC_SHORT: case RPC_FC_USHORT: + pStubMsg->Buffer += sizeof(USHORT); + pStubMsg->MemorySize += sizeof(USHORT); return sizeof(USHORT); case RPC_FC_LONG: case RPC_FC_ULONG: + pStubMsg->Buffer += sizeof(ULONG); + pStubMsg->MemorySize += sizeof(ULONG); return sizeof(ULONG); case RPC_FC_FLOAT: + pStubMsg->Buffer += sizeof(float); + pStubMsg->MemorySize += sizeof(float); return sizeof(float); case RPC_FC_DOUBLE: + pStubMsg->Buffer += sizeof(double); + pStubMsg->MemorySize += sizeof(double); return sizeof(double); case RPC_FC_HYPER: + pStubMsg->Buffer += sizeof(ULONGLONG); + pStubMsg->MemorySize += sizeof(ULONGLONG); return sizeof(ULONGLONG); case RPC_FC_ERROR_STATUS_T: + pStubMsg->Buffer += sizeof(error_status_t); + pStubMsg->MemorySize += sizeof(error_status_t); return sizeof(error_status_t); case RPC_FC_ENUM16: case RPC_FC_ENUM32: + pStubMsg->Buffer += sizeof(INT); + pStubMsg->MemorySize += sizeof(INT); return sizeof(INT); default: FIXME("Unhandled base type: 0x%02x\n", *pFormat); @@ -3229,3 +4764,290 @@ static void WINAPI NdrBaseTypeFree(PMIDL_STUB_MESSAGE pStubMsg, /* nothing to do */ } + +/*********************************************************************** + * NdrClientContextMarshall [RPCRT4.@] + */ +void WINAPI NdrClientContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_CCONTEXT ContextHandle, + int fCheck) +{ + TRACE("(%p, %p, %d)\n", pStubMsg, ContextHandle, fCheck); + + ALIGN_POINTER(pStubMsg->Buffer, 4); + + /* FIXME: what does fCheck do? */ + NDRCContextMarshall(ContextHandle, + pStubMsg->Buffer); + + pStubMsg->Buffer += cbNDRContext; +} + +/*********************************************************************** + * NdrClientContextUnmarshall [RPCRT4.@] + */ +void WINAPI NdrClientContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_CCONTEXT * pContextHandle, + RPC_BINDING_HANDLE BindHandle) +{ + TRACE("(%p, %p, %p)\n", pStubMsg, pContextHandle, BindHandle); + + ALIGN_POINTER(pStubMsg->Buffer, 4); + + NDRCContextUnmarshall(pContextHandle, + BindHandle, + pStubMsg->Buffer, + pStubMsg->RpcMsg->DataRepresentation); + + pStubMsg->Buffer += cbNDRContext; +} + +void WINAPI NdrServerContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_SCONTEXT ContextHandle, + NDR_RUNDOWN RundownRoutine ) +{ + FIXME("(%p, %p, %p): stub\n", pStubMsg, ContextHandle, RundownRoutine); +} + +NDR_SCONTEXT WINAPI NdrServerContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg) +{ + FIXME("(%p): stub\n", pStubMsg); + return NULL; +} + +void WINAPI NdrContextHandleSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p, %p): stub\n", pStubMsg, pMemory, pFormat); +} + +NDR_SCONTEXT WINAPI NdrContextHandleInitialize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p): stub\n", pStubMsg, pFormat); + return NULL; +} + +void WINAPI NdrServerContextNewMarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_SCONTEXT ContextHandle, + NDR_RUNDOWN RundownRoutine, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p, %p, %p): stub\n", pStubMsg, ContextHandle, RundownRoutine, pFormat); +} + +NDR_SCONTEXT WINAPI NdrServerContextNewUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p): stub\n", pStubMsg, pFormat); + return NULL; +} + +#define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e + +typedef struct ndr_context_handle +{ + DWORD attributes; + GUID uuid; +} ndr_context_handle; + +struct context_handle_entry +{ + struct list entry; + DWORD magic; + RPC_BINDING_HANDLE handle; + ndr_context_handle wire_data; +}; + +static struct list context_handle_list = LIST_INIT(context_handle_list); + +static CRITICAL_SECTION ndr_context_cs; +static CRITICAL_SECTION_DEBUG ndr_context_debug = +{ + 0, 0, &ndr_context_cs, + { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") } +}; +static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 }; + +static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext) +{ + struct context_handle_entry *che = (struct context_handle_entry*) CContext; + + if (che->magic != NDR_CONTEXT_HANDLE_MAGIC) + return NULL; + return che; +} + +static struct context_handle_entry *context_entry_from_guid(LPGUID uuid) +{ + struct context_handle_entry *che; + LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry) + if (IsEqualGUID(&che->wire_data.uuid, uuid)) + return che; + return NULL; +} + +RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext) +{ + struct context_handle_entry *che; + RPC_BINDING_HANDLE handle = NULL; + + TRACE("%p\n", CContext); + + EnterCriticalSection(&ndr_context_cs); + che = get_context_entry(CContext); + if (che) + handle = che->handle; + LeaveCriticalSection(&ndr_context_cs); + + if (!handle) + RpcRaiseException(ERROR_INVALID_HANDLE); + return handle; +} + +void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff) +{ + struct context_handle_entry *che; + + TRACE("%p %p\n", CContext, pBuff); + + if (CContext) + { + EnterCriticalSection(&ndr_context_cs); + che = get_context_entry(CContext); + memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle)); + LeaveCriticalSection(&ndr_context_cs); + } + else + { + ndr_context_handle *wire_data = (ndr_context_handle *)pBuff; + wire_data->attributes = 0; + wire_data->uuid = GUID_NULL; + } +} + +static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext, + RPC_BINDING_HANDLE hBinding, + ndr_context_handle *chi) +{ + struct context_handle_entry *che = NULL; + + /* a null UUID means we should free the context handle */ + if (IsEqualGUID(&chi->uuid, &GUID_NULL)) + { + if (*CContext) + { + che = get_context_entry(*CContext); + if (!che) + return ERROR_INVALID_HANDLE; + list_remove(&che->entry); + RpcBindingFree(&che->handle); + HeapFree(GetProcessHeap(), 0, che); + che = NULL; + } + } + /* if there's no existing entry matching the GUID, allocate one */ + else if (!(che = context_entry_from_guid(&chi->uuid))) + { + che = HeapAlloc(GetProcessHeap(), 0, sizeof *che); + if (!che) + return ERROR_NOT_ENOUGH_MEMORY; + che->magic = NDR_CONTEXT_HANDLE_MAGIC; + RpcBindingCopy(hBinding, &che->handle); + list_add_tail(&context_handle_list, &che->entry); + memcpy(&che->wire_data, chi, sizeof *chi); + } + + *CContext = che; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * NDRCContextUnmarshall [RPCRT4.@] + */ +void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext, + RPC_BINDING_HANDLE hBinding, + void *pBuff, ULONG DataRepresentation) +{ + UINT r; + + TRACE("*%p=(%p) %p %p %08x\n", + CContext, *CContext, hBinding, pBuff, DataRepresentation); + + EnterCriticalSection(&ndr_context_cs); + r = ndr_update_context_handle(CContext, hBinding, pBuff); + LeaveCriticalSection(&ndr_context_cs); + if (r) + RpcRaiseException(r); +} + +/*********************************************************************** + * NDRSContextMarshall [RPCRT4.@] + */ +void WINAPI NDRSContextMarshall(NDR_SCONTEXT CContext, + void *pBuff, + NDR_RUNDOWN userRunDownIn) +{ + FIXME("(%p %p %p): stub\n", CContext, pBuff, userRunDownIn); +} + +/*********************************************************************** + * NDRSContextMarshallEx [RPCRT4.@] + */ +void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding, + NDR_SCONTEXT CContext, + void *pBuff, + NDR_RUNDOWN userRunDownIn) +{ + FIXME("(%p %p %p %p): stub\n", hBinding, CContext, pBuff, userRunDownIn); +} + +/*********************************************************************** + * NDRSContextMarshall2 [RPCRT4.@] + */ +void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding, + NDR_SCONTEXT CContext, + void *pBuff, + NDR_RUNDOWN userRunDownIn, + void *CtxGuard, ULONG Flags) +{ + FIXME("(%p %p %p %p %p %u): stub\n", + hBinding, CContext, pBuff, userRunDownIn, CtxGuard, Flags); +} + +/*********************************************************************** + * NDRSContextUnmarshall [RPCRT4.@] + */ +NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff, + ULONG DataRepresentation) +{ + FIXME("(%p %08x): stub\n", pBuff, DataRepresentation); + return NULL; +} + +/*********************************************************************** + * NDRSContextUnmarshallEx [RPCRT4.@] + */ +NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding, + void *pBuff, + ULONG DataRepresentation) +{ + FIXME("(%p %p %08x): stub\n", hBinding, pBuff, DataRepresentation); + return NULL; +} + +/*********************************************************************** + * NDRSContextUnmarshall2 [RPCRT4.@] + */ +NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding, + void *pBuff, + ULONG DataRepresentation, + void *CtxGuard, ULONG Flags) +{ + FIXME("(%p %p %08x %p %u): stub\n", + hBinding, pBuff, DataRepresentation, CtxGuard, Flags); + return NULL; +} diff --git a/reactos/dll/win32/rpcrt4/ndr_midl.c b/reactos/dll/win32/rpcrt4/ndr_midl.c deleted file mode 100644 index e8243ef8ff0..00000000000 --- a/reactos/dll/win32/rpcrt4/ndr_midl.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * MIDL proxy/stub stuff - * - * Copyright 2002 Ove Kåven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions - */ - -#include -#include -#include -#include - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "objbase.h" - -#include "rpcproxy.h" - -#include "wine/debug.h" - -#include "cpsf.h" -#include "ndr_misc.h" -#include "rpcndr.h" - -WINE_DEFAULT_DEBUG_CHANNEL(rpc); - -/*********************************************************************** - * NdrProxyInitialize [RPCRT4.@] - */ -void WINAPI NdrProxyInitialize(void *This, - PRPC_MESSAGE pRpcMsg, - PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDescriptor, - unsigned int ProcNum) -{ - HRESULT hr; - - TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); - NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); - if (This) StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer); - if (pStubMsg->pRpcChannelBuffer) { - hr = IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer, - &pStubMsg->dwDestContext, - &pStubMsg->pvDestContext); - } - TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer); -} - -/*********************************************************************** - * NdrProxyGetBuffer [RPCRT4.@] - */ -void WINAPI NdrProxyGetBuffer(void *This, - PMIDL_STUB_MESSAGE pStubMsg) -{ - HRESULT hr; - const IID *riid = NULL; - - TRACE("(%p,%p)\n", This, pStubMsg); - pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; - pStubMsg->dwStubPhase = PROXY_GETBUFFER; - hr = StdProxy_GetIID(This, &riid); - hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer, - (RPCOLEMESSAGE*)pStubMsg->RpcMsg, - riid); - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; - pStubMsg->dwStubPhase = PROXY_MARSHAL; -} - -/*********************************************************************** - * NdrProxySendReceive [RPCRT4.@] - */ -void WINAPI NdrProxySendReceive(void *This, - PMIDL_STUB_MESSAGE pStubMsg) -{ - ULONG Status = 0; - HRESULT hr; - - TRACE("(%p,%p)\n", This, pStubMsg); - - if (!pStubMsg->pRpcChannelBuffer) - { - WARN("Trying to use disconnected proxy %p\n", This); - RpcRaiseException(RPC_E_DISCONNECTED); - } - - pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; - hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer, - (RPCOLEMESSAGE*)pStubMsg->RpcMsg, - &Status); - pStubMsg->dwStubPhase = PROXY_UNMARSHAL; - pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; - - /* raise exception if call failed */ - if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); - else if (FAILED(hr)) RpcRaiseException(hr); -} - -/*********************************************************************** - * NdrProxyFreeBuffer [RPCRT4.@] - */ -void WINAPI NdrProxyFreeBuffer(void *This, - PMIDL_STUB_MESSAGE pStubMsg) -{ - HRESULT hr; - - TRACE("(%p,%p)\n", This, pStubMsg); - hr = IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer, - (RPCOLEMESSAGE*)pStubMsg->RpcMsg); -} - -/*********************************************************************** - * NdrProxyErrorHandler [RPCRT4.@] - */ -HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode) -{ - WARN("(0x%08lx): a proxy call failed\n", dwExceptionCode); - - if (FAILED(dwExceptionCode)) - return dwExceptionCode; - else - return HRESULT_FROM_WIN32(dwExceptionCode); -} - -/*********************************************************************** - * NdrStubInitialize [RPCRT4.@] - */ -void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg, - PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDescriptor, - LPRPCCHANNELBUFFER pRpcChannelBuffer) -{ - TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer); - NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor); - pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; -} - -/*********************************************************************** - * NdrStubGetBuffer [RPCRT4.@] - */ -void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER This, - LPRPCCHANNELBUFFER pRpcChannelBuffer, - PMIDL_STUB_MESSAGE pStubMsg) -{ - TRACE("(%p,%p)\n", This, pStubMsg); - pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; - pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; - I_RpcGetBuffer(pStubMsg->RpcMsg); /* ? */ - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; -} - -/************************************************************************ - * NdrClientInitializeNew [RPCRT4.@] - */ -void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum ) -{ - TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n", - pRpcMessage, pStubMsg, pStubDesc, ProcNum); - - assert( pRpcMessage && pStubMsg && pStubDesc ); - - memset(pRpcMessage, 0, sizeof(RPC_MESSAGE)); - pRpcMessage->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; - - /* not everyone allocates stack space for w2kReserved */ - memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); - - pStubMsg->ReuseBuffer = FALSE; - pStubMsg->IsClient = TRUE; - pStubMsg->StubDesc = pStubDesc; - pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; - pStubMsg->pfnFree = pStubDesc->pfnFree; - pStubMsg->RpcMsg = pRpcMessage; - - pRpcMessage->ProcNum = ProcNum; - pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; -} - -/*********************************************************************** - * NdrServerInitializeNew [RPCRT4.@] - */ -unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDesc ) -{ - TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc); - - assert( pRpcMsg && pStubMsg && pStubDesc ); - - /* not everyone allocates stack space for w2kReserved */ - memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); - - pStubMsg->ReuseBuffer = TRUE; - pStubMsg->IsClient = FALSE; - pStubMsg->StubDesc = pStubDesc; - pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; - pStubMsg->pfnFree = pStubDesc->pfnFree; - pStubMsg->RpcMsg = pRpcMsg; - pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; - pStubMsg->BufferLength = pRpcMsg->BufferLength; - pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength; - - /* FIXME: determine the proper return value */ - return NULL; -} - -/*********************************************************************** - * NdrGetBuffer [RPCRT4.@] - */ -unsigned char *WINAPI NdrGetBuffer(MIDL_STUB_MESSAGE *stubmsg, unsigned long buflen, RPC_BINDING_HANDLE handle) -{ - TRACE("(stubmsg == ^%p, buflen == %lu, handle == %p): wild guess.\n", stubmsg, buflen, handle); - - assert( stubmsg && stubmsg->RpcMsg ); - - /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ - stubmsg->RpcMsg->Handle = handle; - - stubmsg->RpcMsg->BufferLength = buflen; - if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) - return NULL; - - stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; - stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; - stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength; - return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer); -} -/*********************************************************************** - * NdrFreeBuffer [RPCRT4.@] - */ -void WINAPI NdrFreeBuffer(MIDL_STUB_MESSAGE *pStubMsg) -{ - TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg); - I_RpcFreeBuffer(pStubMsg->RpcMsg); - pStubMsg->BufferLength = 0; - pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL); -} - -/************************************************************************ - * NdrSendReceive [RPCRT4.@] - */ -unsigned char *WINAPI NdrSendReceive( MIDL_STUB_MESSAGE *stubmsg, unsigned char *buffer ) -{ - RPC_STATUS status; - - TRACE("(stubmsg == ^%p, buffer == ^%p)\n", stubmsg, buffer); - - /* FIXME: how to handle errors? (raise exception?) */ - if (!stubmsg) { - ERR("NULL stub message. No action taken.\n"); - return NULL; - } - if (!stubmsg->RpcMsg) { - ERR("RPC Message not present in stub message. No action taken.\n"); - return NULL; - } - - status = I_RpcSendReceive(stubmsg->RpcMsg); - if (status != RPC_S_OK) - { - WARN("I_RpcSendReceive did not return success.\n"); - /* FIXME: raise exception? */ - //RpcRaiseException(status); - } - - stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; - stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; - stubmsg->BufferEnd = stubmsg->BufferStart + stubmsg->BufferLength; - stubmsg->Buffer = stubmsg->BufferStart; - - /* FIXME: is this the right return value? */ - return NULL; -} - -/************************************************************************ - * NdrMapCommAndFaultStatus [RPCRT4.@] - */ -RPC_STATUS RPC_ENTRY NdrMapCommAndFaultStatus( PMIDL_STUB_MESSAGE pStubMsg, - unsigned long *pCommStatus, - unsigned long *pFaultStatus, - RPC_STATUS Status ) -{ - FIXME("(%p, %p, %p, %ld): stub\n", pStubMsg, pCommStatus, pFaultStatus, Status); - - *pCommStatus = 0; - *pFaultStatus = 0; - - return RPC_S_OK; -} - -/************************************************************************ - * NdrStubForwardingFunction [RPCRT4.@] - */ -void __RPC_STUB NdrStubForwardingFunction( IRpcStubBuffer *This, IRpcChannelBuffer *pChannel, - PRPC_MESSAGE pMsg, DWORD *pdwStubPhase ) -{ - FIXME("Not implemented\n"); - return; -} diff --git a/reactos/dll/win32/rpcrt4/ndr_misc.h b/reactos/dll/win32/rpcrt4/ndr_misc.h index 0abeaed5b04..ebd70b8d826 100644 --- a/reactos/dll/win32/rpcrt4/ndr_misc.h +++ b/reactos/dll/win32/rpcrt4/ndr_misc.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_NDR_MISC_H @@ -30,22 +30,36 @@ struct IPSFactoryBuffer; -#define ComputeConformance(pStubMsg, pMemory, pFormat, def) ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat, def, &pStubMsg->MaxCount) -#define ComputeVariance(pStubMsg, pMemory, pFormat, def) ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat, def, &pStubMsg->ActualCount) PFORMAT_STRING ComputeConformanceOrVariance( MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, - PFORMAT_STRING pFormat, ULONG_PTR def, ULONG *pCount); + PFORMAT_STRING pFormat, ULONG_PTR def, ULONG_PTR *pCount); + +static inline PFORMAT_STRING ComputeConformance(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, ULONG def) +{ + return ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat, def, &pStubMsg->MaxCount); +} + +static inline PFORMAT_STRING ComputeVariance(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, ULONG def) +{ + PFORMAT_STRING ret; + ULONG_PTR ActualCount = pStubMsg->ActualCount; + + pStubMsg->Offset = 0; + ret = ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat, def, &ActualCount); + pStubMsg->ActualCount = (ULONG)ActualCount; + return ret; +} typedef unsigned char* (WINAPI *NDR_MARSHALL) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); typedef unsigned char* (WINAPI *NDR_UNMARSHALL)(PMIDL_STUB_MESSAGE, unsigned char**,PFORMAT_STRING, unsigned char); typedef void (WINAPI *NDR_BUFFERSIZE)(PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); -typedef unsigned long (WINAPI *NDR_MEMORYSIZE)(PMIDL_STUB_MESSAGE, PFORMAT_STRING); +typedef ULONG (WINAPI *NDR_MEMORYSIZE)(PMIDL_STUB_MESSAGE, PFORMAT_STRING); typedef void (WINAPI *NDR_FREE) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); -extern NDR_MARSHALL NdrMarshaller[]; -extern NDR_UNMARSHALL NdrUnmarshaller[]; -extern NDR_BUFFERSIZE NdrBufferSizer[]; -extern NDR_MEMORYSIZE NdrMemorySizer[]; -extern NDR_FREE NdrFreer[]; +extern const NDR_MARSHALL NdrMarshaller[]; +extern const NDR_UNMARSHALL NdrUnmarshaller[]; +extern const NDR_BUFFERSIZE NdrBufferSizer[]; +extern const NDR_MEMORYSIZE NdrMemorySizer[]; +extern const NDR_FREE NdrFreer[]; #endif /* __WINE_NDR_MISC_H */ diff --git a/reactos/dll/win32/rpcrt4/ndr_ole.c b/reactos/dll/win32/rpcrt4/ndr_ole.c index 4bdeefe633d..b65e18b0a1b 100644 --- a/reactos/dll/win32/rpcrt4/ndr_ole.c +++ b/reactos/dll/win32/rpcrt4/ndr_ole.c @@ -15,12 +15,10 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions - * - what are the marshalling functions supposed to return? + * - fix the wire-protocol to match MS/RPC * - finish RpcStream_Vtbl */ @@ -41,7 +39,9 @@ #include "ndr_misc.h" #include "rpcndr.h" +#include "rpcproxy.h" #include "wine/rpcfc.h" +#include "cpsf.h" #include "wine/debug.h" @@ -112,7 +112,7 @@ static ULONG WINAPI RpcStream_Release(LPSTREAM iface) { RpcStreamImpl *This = (RpcStreamImpl *)iface; if (!--(This->RefCount)) { - TRACE("size=%ld\n", *This->size); + TRACE("size=%d\n", *This->size); This->pMsg->Buffer = (unsigned char*)This->data + *This->size; HeapFree(GetProcessHeap(),0,This); return 0; @@ -219,7 +219,7 @@ static LPSTREAM RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init) This->data = (char*)(This->size + 1); This->pos = 0; if (init) *This->size = 0; - TRACE("init size=%ld\n", *This->size); + TRACE("init size=%d\n", *This->size); return (LPSTREAM)This; } @@ -254,7 +254,7 @@ unsigned char * WINAPI NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); pStubMsg->MaxCount = 0; if (!LoadCOM()) return NULL; - if (pStubMsg->Buffer + sizeof(DWORD) < (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength) { + if (pStubMsg->Buffer + sizeof(DWORD) <= (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength) { stream = RpcStream_Create(pStubMsg, TRUE); if (stream) { if (pMemory) @@ -288,12 +288,14 @@ unsigned char * WINAPI NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg *(LPVOID*)ppMemory = NULL; if (pStubMsg->Buffer + sizeof(DWORD) < (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength) { stream = RpcStream_Create(pStubMsg, FALSE); - if (stream) { + if (!stream) RpcRaiseException(E_OUTOFMEMORY); + if (*((RpcStreamImpl *)stream)->size != 0) hr = COM_UnmarshalInterface(stream, &IID_NULL, (LPVOID*)ppMemory); - IStream_Release(stream); - if (FAILED(hr)) + else + hr = S_OK; + IStream_Release(stream); + if (FAILED(hr)) RpcRaiseException(hr); - } } return NULL; } @@ -314,18 +316,27 @@ void WINAPI NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, hr = COM_GetMarshalSizeMax(&size, riid, (LPUNKNOWN)pMemory, pStubMsg->dwDestContext, pStubMsg->pvDestContext, MSHLFLAGS_NORMAL); - TRACE("size=%ld\n", size); + TRACE("size=%d\n", size); pStubMsg->BufferLength += sizeof(DWORD) + size; } /*********************************************************************** * NdrInterfacePointerMemorySize [RPCRT4.@] */ -unsigned long WINAPI NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) +ULONG WINAPI NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) { - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - return 0; + ULONG size; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + size = *(ULONG *)pStubMsg->Buffer; + pStubMsg->Buffer += 4; + pStubMsg->MemorySize += 4; + + pStubMsg->Buffer += size; + + return pStubMsg->MemorySize; } /*********************************************************************** @@ -357,3 +368,27 @@ void WINAPI NdrOleFree(void *NodeToFree) if (!LoadCOM()) return; COM_MemFree(NodeToFree); } + +/*********************************************************************** + * Helper function to create a stub. + * This probably looks very much like NdrpCreateStub. + */ +HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub) +{ + 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_CreateStub(psfac, iid, pUnk, ppstub); + + IPSFactoryBuffer_Release(psfac); + return r; +} diff --git a/reactos/dll/win32/rpcrt4/ndr_stubless.c b/reactos/dll/win32/rpcrt4/ndr_stubless.c index ec31fda0935..dbe500ef7b6 100644 --- a/reactos/dll/win32/rpcrt4/ndr_stubless.c +++ b/reactos/dll/win32/rpcrt4/ndr_stubless.c @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: * - Pipes @@ -89,17 +89,23 @@ static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemor { NDR_FREE m = NdrFreer[pFormat[0] & NDR_TABLE_MASK]; if (m) m(pStubMsg, pMemory, pFormat); - else - { - FIXME("format type 0x%x not implemented\n", pFormat[0]); - RpcRaiseException(RPC_X_BAD_STUB_DATA); - } } static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) { NDR_MEMORYSIZE m = NdrMemorySizer[pFormat[0] & NDR_TABLE_MASK]; - if (m) return m(pStubMsg, pFormat); + if (m) + { + unsigned char *saved_buffer = pStubMsg->Buffer; + unsigned long ret; + int saved_ignore_embedded_pointers = pStubMsg->IgnoreEmbeddedPointers; + pStubMsg->MemorySize = 0; + pStubMsg->IgnoreEmbeddedPointers = 1; + ret = m(pStubMsg, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded_pointers; + pStubMsg->Buffer = saved_buffer; + return ret; + } else { FIXME("format type 0x%x not implemented\n", pFormat[0]); @@ -198,63 +204,12 @@ typedef struct _NDR_PROC_PARTIAL_OIF_HEADER * sizing pass */ unsigned short constant_server_buffer_size; - /* -Oif flags: - * RPC_FC_PROC_OI2F_SRVMUSTSIZE = 0x01 - the server must perform a - * sizing pass. - * RPC_FC_PROC_OI2F_CLTMUSTSIZE = 0x02 - the client must perform a - * sizing pass. - * RPC_FC_PROC_OI2F_HASRETURN = 0x04 - procedure has a return value. - * RPC_FC_PROC_OI2F_HASPIPES = 0x08 - the pipe package should be used. - * RPC_FC_PROC_OI2F_HASASYNCUUID = 0x20 - indicates an asynchronous DCOM - * procedure. - * RPC_FC_PROC_OI2F_HASEXTS = 0x40 - indicates that Windows 2000 - * extensions are in use. - * RPC_FC_PROC_OI2F_HASASYNCHND = 0x80 - indicates an asynchronous RPC - * procedure. - */ - unsigned char Oif_flags; + INTERPRETER_OPT_FLAGS Oi2Flags; /* number of params */ unsigned char number_of_params; } NDR_PROC_PARTIAL_OIF_HEADER; -/* Windows 2000 extensions */ -typedef struct _NDR_PROC_EXTENSION -{ - /* size in bytes of all following extensions */ - unsigned char extension_version; - - /* extension flags: - * HasNewCorrDesc = 0x01 - indicates new correlation descriptors in use - * ClientCorrCheck = 0x02 - client needs correlation check - * ServerCorrCheck = 0x04 - server needs correlation check - * HasNotify = 0x08 - should call MIDL [notify] routine @ NotifyIndex - * HasNotify2 = 0x10 - should call MIDL [notify_flag] routine @ - * NotifyIndex - */ - unsigned char ext_flags; - - /* client cache size hint */ - unsigned short ClientCorrHint; - - /* server cache size hint */ - unsigned short ServerCorrHint; - - /* index of routine in MIDL_STUB_DESC::NotifyRoutineTable to call if - * HasNotify or HasNotify2 flag set */ - unsigned short NotifyIndex; -} NDR_PROC_EXTENSION; - -/* usually generated only on IA64 */ -typedef struct _NDR_PROC_EXTENSION_64 -{ - NDR_PROC_EXTENSION ext; - - /* needed only on IA64 to cope with float/register loading */ - unsigned short FloatDoubleMask; -} NDR_PROC_EXTENSION_64; - - typedef struct _NDR_PARAM_OI_BASETYPE { /* parameter direction. One of: @@ -406,8 +361,393 @@ static void WINAPI dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes) if (param_attributes.ServerAllocSize) TRACE(" ServerAllocSize = %d", param_attributes.ServerAllocSize * 8); } -/* FIXME: this will be different on other plaftorms than i386 */ -#define ARG_FROM_OFFSET(args, offset) (*(unsigned char **)args + offset) +static void WINAPI dump_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags) +{ + if (Oi2Flags.ServerMustSize) TRACE(" ServerMustSize"); + if (Oi2Flags.ClientMustSize) TRACE(" ClientMustSize"); + if (Oi2Flags.HasReturn) TRACE(" HasReturn"); + if (Oi2Flags.HasPipes) TRACE(" HasPipes"); + if (Oi2Flags.Unused) TRACE(" Unused"); + if (Oi2Flags.HasAsyncUuid) TRACE(" HasAsyncUuid"); + if (Oi2Flags.HasExtensions) TRACE(" HasExtensions"); + if (Oi2Flags.HasAsyncHandle) TRACE(" HasAsyncHandle"); + TRACE("\n"); +} + +#define ARG_FROM_OFFSET(stubMsg, offset) ((stubMsg).StackTop + (offset)) + +static PFORMAT_STRING client_get_handle( + PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader, + PFORMAT_STRING pFormat, handle_t *phBinding) +{ + /* binding */ + switch (pProcHeader->handle_type) + { + /* explicit binding: parse additional section */ + case RPC_FC_BIND_EXPLICIT: + switch (*pFormat) /* handle_type */ + { + case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ + { + const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat; + + TRACE("Explicit primitive handle @ %d\n", pDesc->offset); + + if (pDesc->flag) /* pointer to binding */ + *phBinding = **(handle_t **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + else + *phBinding = *(handle_t *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + return pFormat + sizeof(NDR_EHD_PRIMITIVE); + } + case RPC_FC_BIND_GENERIC: /* explicit generic */ + { + const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat; + void *pObject = NULL; + void *pArg; + const GENERIC_BINDING_ROUTINE_PAIR *pGenPair; + + TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index); + + if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR) + pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + else + pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf); + pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index]; + *phBinding = pGenPair->pfnBind(pObject); + return pFormat + sizeof(NDR_EHD_GENERIC); + } + case RPC_FC_BIND_CONTEXT: /* explicit context */ + { + const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat; + NDR_CCONTEXT context_handle; + TRACE("Explicit bind context\n"); + if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR) + { + TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n"); + context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + } + else + context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + if ((pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL) && + !context_handle) + { + ERR("null context handle isn't allowed\n"); + RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT); + return NULL; + } + *phBinding = NDRCContextBinding(context_handle); + /* FIXME: should we store this structure in stubMsg.pContext? */ + return pFormat + sizeof(NDR_EHD_CONTEXT); + } + default: + ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + break; + case RPC_FC_BIND_GENERIC: /* implicit generic */ + FIXME("RPC_FC_BIND_GENERIC\n"); + RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */ + break; + case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */ + TRACE("Implicit primitive handle\n"); + *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle; + break; + case RPC_FC_CALLBACK_HANDLE: /* implicit callback */ + FIXME("RPC_FC_CALLBACK_HANDLE\n"); + break; + case RPC_FC_AUTO_HANDLE: /* implicit auto handle */ + /* strictly speaking, it isn't necessary to set hBinding here + * since it isn't actually used (hence the automatic in its name), + * but then why does MIDL generate a valid entry in the + * MIDL_STUB_DESC for it? */ + TRACE("Implicit auto handle\n"); + *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle; + break; + default: + ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + return pFormat; +} + +static void client_free_handle( + PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader, + PFORMAT_STRING pFormat, handle_t hBinding) +{ + /* binding */ + switch (pProcHeader->handle_type) + { + /* explicit binding: parse additional section */ + case RPC_FC_BIND_EXPLICIT: + switch (*pFormat) /* handle_type */ + { + case RPC_FC_BIND_GENERIC: /* explicit generic */ + { + const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat; + void *pObject = NULL; + void *pArg; + const GENERIC_BINDING_ROUTINE_PAIR *pGenPair; + + TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index); + + if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR) + pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + else + pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf); + pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index]; + pGenPair->pfnUnbind(pObject, hBinding); + break; + } + case RPC_FC_BIND_CONTEXT: /* explicit context */ + case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ + break; + default: + ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + break; + case RPC_FC_BIND_GENERIC: /* implicit generic */ + FIXME("RPC_FC_BIND_GENERIC\n"); + RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */ + break; + case RPC_FC_CALLBACK_HANDLE: /* implicit callback */ + case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */ + case RPC_FC_AUTO_HANDLE: /* implicit auto handle */ + break; + default: + ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static void client_do_args(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, + int phase, unsigned short number_of_params, unsigned char *pRetVal) +{ + /* current format string offset */ + int current_offset = 0; + /* current stack offset */ + unsigned short current_stack_offset = 0; + /* counter */ + unsigned short i; + + for (i = 0; i < number_of_params; i++) + { + const NDR_PARAM_OIF_BASETYPE *pParam = + (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset]; + unsigned char * pArg; + + current_stack_offset = pParam->stack_offset; + pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset); + + TRACE("param[%d]: new format\n", i); + TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n"); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset); + TRACE("\tmemory addr (before): %p\n", pArg); + + if (pParam->param_attributes.IsBasetype) + { + const unsigned char * pTypeFormat = + &pParam->type_format_char; + + if (pParam->param_attributes.IsSimpleRef) + pArg = *(unsigned char **)pArg; + + TRACE("\tbase type: 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_attributes.IsIn) + call_buffer_sizer(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_MARSHAL: + if (pParam->param_attributes.IsIn) + call_marshaller(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_UNMARSHAL: + if (pParam->param_attributes.IsOut) + { + if (pParam->param_attributes.IsReturn) + call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0); + else + call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0); + TRACE("pRetVal = %p\n", pRetVal); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_offset += sizeof(NDR_PARAM_OIF_BASETYPE); + } + else + { + const NDR_PARAM_OIF_OTHER *pParamOther = + (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset]; + + const unsigned char * pTypeFormat = + &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]); + + /* if a simple ref pointer then we have to do the + * check for the pointer being non-NULL. */ + if (pParam->param_attributes.IsSimpleRef) + { + if (!*(unsigned char **)pArg) + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + + TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_attributes.IsIn) + { + if (pParam->param_attributes.IsByValue) + call_buffer_sizer(pStubMsg, pArg, pTypeFormat); + else + call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + } + break; + case PROXY_MARSHAL: + if (pParam->param_attributes.IsIn) + { + if (pParam->param_attributes.IsByValue) + call_marshaller(pStubMsg, pArg, pTypeFormat); + else + call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + } + break; + case PROXY_UNMARSHAL: + if (pParam->param_attributes.IsOut) + { + if (pParam->param_attributes.IsReturn) + call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0); + else if (pParam->param_attributes.IsByValue) + call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0); + else + call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_offset += sizeof(NDR_PARAM_OIF_OTHER); + } + TRACE("\tmemory addr (after): %p\n", pArg); + } +} + +static void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat, int phase, unsigned short stack_size, + unsigned char *pRetVal, BOOL object_proc) +{ + /* current format string offset */ + int current_offset = 0; + /* current stack offset */ + unsigned short current_stack_offset = 0; + /* counter */ + unsigned short i; + + /* NOTE: V1 style format does't terminate on the number_of_params + * condition as it doesn't have this attribute. Instead it + * terminates when the stack size given in the header is exceeded. + */ + for (i = 0; TRUE; i++) + { + const NDR_PARAM_OI_BASETYPE *pParam = + (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset]; + /* note: current_stack_offset starts after the This pointer + * if present, so adjust this */ + unsigned short current_stack_offset_adjusted = current_stack_offset + + (object_proc ? sizeof(void *) : 0); + unsigned char * pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset_adjusted); + + /* no more parameters; exit loop */ + if (current_stack_offset_adjusted >= stack_size) + break; + + TRACE("param[%d]: old format\n", i); + TRACE("\tparam_direction: 0x%x\n", pParam->param_direction); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted); + TRACE("\tmemory addr (before): %p\n", pArg); + + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE || + pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + { + const unsigned char * pTypeFormat = + &pParam->type_format_char; + + TRACE("\tbase type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_buffer_sizer(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_MARSHAL: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_marshaller(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_UNMARSHAL: + if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + { + if (pParam->param_direction & RPC_FC_RETURN_PARAM) + call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0); + else + call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat); + current_offset += sizeof(NDR_PARAM_OI_BASETYPE); + } + else + { + const NDR_PARAM_OI_OTHER *pParamOther = + (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset]; + + const unsigned char *pTypeFormat = + &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]; + + TRACE("\tcomplex type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_direction == RPC_FC_IN_PARAM || + pParam->param_direction & RPC_FC_IN_OUT_PARAM) + call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + break; + case PROXY_MARSHAL: + if (pParam->param_direction == RPC_FC_IN_PARAM || + pParam->param_direction & RPC_FC_IN_OUT_PARAM) + call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + break; + case PROXY_UNMARSHAL: + if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_OUT_PARAM) + call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0); + else if (pParam->param_direction == RPC_FC_RETURN_PARAM) + call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0); + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_stack_offset += pParamOther->stack_size * sizeof(INT); + current_offset += sizeof(NDR_PARAM_OI_OTHER); + } + TRACE("\tmemory addr (after): %p\n", pArg); + } +} /* the return type should be CLIENT_CALL_RETURN, but this is incompatible * with the way gcc returns structures. "void *" should be the largest type @@ -415,8 +755,6 @@ static void WINAPI dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes) LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, ...) { /* pointer to start of stack where arguments start */ - /* FIXME: not portable */ - unsigned char *args = (unsigned char *)(&pFormat+1); RPC_MESSAGE rpcMsg; MIDL_STUB_MESSAGE stubMsg; handle_t hBinding = NULL; @@ -424,192 +762,128 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma unsigned short procedure_number; /* size of stack */ unsigned short stack_size; - /* current stack offset */ - unsigned short current_stack_offset; /* number of parameters. optional for client to give it to us */ unsigned char number_of_params = ~0; - /* counter */ - unsigned short i; /* cache of Oif_flags from v2 procedure header */ - unsigned char Oif_flags = 0; - /* cache of extension flags from NDR_PROC_EXTENSION */ - unsigned char ext_flags = 0; + 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]; - /* offset in format string for start of params */ - int parameter_start_offset; - /* current format string offset */ - int current_offset; /* -Oif or -Oicf generated format */ BOOL bV2Format = FALSE; /* the value to return to the client from the remote procedure */ LONG_PTR RetVal = 0; /* the pointer to the object when in OLE mode */ void * This = NULL; + PFORMAT_STRING pHandleFormat; TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat); - TRACE("&first_argument = %p -> %p\n", args, ARG_FROM_OFFSET(args, 0)); /* Later NDR language versions probably won't be backwards compatible */ if (pStubDesc->Version > 0x50002) { - FIXME("Incompatible stub description version: 0x%lx\n", pStubDesc->Version); + FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version); RpcRaiseException(RPC_X_WRONG_STUB_VERSION); } if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) { - NDR_PROC_HEADER_RPC * pProcHeader = (NDR_PROC_HEADER_RPC *)&pFormat[0]; + const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0]; stack_size = pProcHeader->stack_size; procedure_number = pProcHeader->proc_num; - current_offset = sizeof(NDR_PROC_HEADER_RPC); + pFormat += sizeof(NDR_PROC_HEADER_RPC); } else { stack_size = pProcHeader->stack_size; procedure_number = pProcHeader->proc_num; - TRACE("proc num: %d\n", procedure_number); - current_offset = sizeof(NDR_PROC_HEADER); + pFormat += sizeof(NDR_PROC_HEADER); } + TRACE("stack size: 0x%x\n", 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) + stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT); + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + /* object is always the first argument */ + This = **(void *const **)(&pFormat+1); + NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number); + } + else + NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number); TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags); - TRACE("MIDL stub version = 0x%lx\n", pStubDesc->MIDLVersion); + TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion); + + /* needed for conformance of top-level objects */ +#ifdef __i386__ + stubMsg.StackTop = *(unsigned char **)(&pFormat+1); +#else +# warning Stack not retrieved for your CPU architecture +#endif + + pHandleFormat = pFormat; /* we only need a handle if this isn't an object method */ if (!(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)) { - /* binding */ - switch (pProcHeader->handle_type) - { - /* explicit binding: parse additional section */ - case RPC_FC_BIND_EXPLICIT: - switch (pFormat[current_offset]) /* handle_type */ - { - case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ - { - NDR_EHD_PRIMITIVE * pDesc = (NDR_EHD_PRIMITIVE *)&pFormat[current_offset]; - - TRACE("Explicit primitive handle @ %d\n", pDesc->offset); - - if (pDesc->flag) /* pointer to binding */ - hBinding = **(handle_t **)ARG_FROM_OFFSET(args, pDesc->offset); - else - hBinding = *(handle_t *)ARG_FROM_OFFSET(args, pDesc->offset); - current_offset += sizeof(NDR_EHD_PRIMITIVE); - break; - } - case RPC_FC_BIND_GENERIC: /* explicit generic */ - FIXME("RPC_FC_BIND_GENERIC\n"); - RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */ - current_offset += sizeof(NDR_EHD_GENERIC); - break; - case RPC_FC_BIND_CONTEXT: /* explicit context */ - { - NDR_EHD_CONTEXT * pDesc = (NDR_EHD_CONTEXT *)&pFormat[current_offset]; - TRACE("Explicit bind context\n"); - hBinding = NDRCContextBinding(*(NDR_CCONTEXT *)ARG_FROM_OFFSET(args, pDesc->offset)); - /* FIXME: should we store this structure in stubMsg.pContext? */ - current_offset += sizeof(NDR_EHD_CONTEXT); - break; - } - default: - ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); - RpcRaiseException(RPC_X_BAD_STUB_DATA); - } - break; - case RPC_FC_BIND_GENERIC: /* implicit generic */ - FIXME("RPC_FC_BIND_GENERIC\n"); - RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */ - break; - case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */ - TRACE("Implicit primitive handle\n"); - hBinding = *pStubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle; - break; - case RPC_FC_CALLBACK_HANDLE: /* implicit callback */ - FIXME("RPC_FC_CALLBACK_HANDLE\n"); - break; - case RPC_FC_AUTO_HANDLE: /* implicit auto handle */ - /* strictly speaking, it isn't necessary to set hBinding here - * since it isn't actually used (hence the automatic in its name), - * but then why does MIDL generate a valid entry in the - * MIDL_STUB_DESC for it? */ - TRACE("Implicit auto handle\n"); - hBinding = *pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle; - break; - default: - ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type); - RpcRaiseException(RPC_X_BAD_STUB_DATA); - } + pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding); + if (!pFormat) return 0; } bV2Format = (pStubDesc->Version >= 0x20000); if (bV2Format) { - NDR_PROC_PARTIAL_OIF_HEADER * pOIFHeader = - (NDR_PROC_PARTIAL_OIF_HEADER*)&pFormat[current_offset]; + const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = + (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat; - Oif_flags = pOIFHeader->Oif_flags; + Oif_flags = pOIFHeader->Oi2Flags; number_of_params = pOIFHeader->number_of_params; - current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER); + pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER); } - TRACE("Oif_flags = 0x%02x\n", Oif_flags); + TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags); - if (Oif_flags & RPC_FC_PROC_OI2F_HASEXTS) + if (Oif_flags.HasExtensions) { - NDR_PROC_EXTENSION * pExtensions = - (NDR_PROC_EXTENSION *)&pFormat[current_offset]; - ext_flags = pExtensions->ext_flags; - current_offset += pExtensions->extension_version; + const NDR_PROC_HEADER_EXTS *pExtensions = + (const NDR_PROC_HEADER_EXTS *)pFormat; + ext_flags = pExtensions->Flags2; + pFormat += pExtensions->Size; } - if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) - { - /* object is always the first argument */ - This = *(void **)ARG_FROM_OFFSET(args, 0); - NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number); - } - else - NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number); - - /* create the full pointer translation tables, if requested */ - if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) -#if 0 - stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT); -#else - FIXME("initialize full pointer translation tables\n"); -#endif - stubMsg.BufferLength = 0; /* store the RPC flags away */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) - rpcMsg.RpcFlags = ((NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; + rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; /* use alternate memory allocation routines */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC) NdrRpcSmSetClientToOsf(&stubMsg); - if (Oif_flags & RPC_FC_PROC_OI2F_HASPIPES) + 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 & RPC_FC_PROC_EXT_NEWCORRDESC) + if (ext_flags.HasNewCorrDesc) { /* initialize extra correlation package */ FIXME("new correlation description not implemented\n"); stubMsg.fHasNewCorrDesc = TRUE; } - parameter_start_offset = current_offset; - /* order of phases: * 1. PROXY_CALCSIZE - calculate the buffer size * 2. PROXY_GETBUFFER - allocate the buffer @@ -626,7 +900,7 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma /* allocate the buffer */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) NdrProxyGetBuffer(This, &stubMsg); - else if (Oif_flags & RPC_FC_PROC_OI2F_HASPIPES) + else if (Oif_flags.HasPipes) /* NdrGetPipeBuffer(...) */ FIXME("pipes not supported yet\n"); else @@ -646,7 +920,7 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma * params */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) NdrProxySendReceive(This, &stubMsg); - else if (Oif_flags & RPC_FC_PROC_OI2F_HASPIPES) + else if (Oif_flags.HasPipes) /* NdrPipesSendReceive(...) */ FIXME("pipes not supported yet\n"); else @@ -670,213 +944,13 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma case PROXY_CALCSIZE: case PROXY_MARSHAL: case PROXY_UNMARSHAL: - current_offset = parameter_start_offset; - current_stack_offset = 0; - - /* NOTE: V1 style format does't terminate on the number_of_params - * condition as it doesn't have this attribute. Instead it - * terminates when the stack size given in the header is exceeded. - */ - for (i = 0; i < number_of_params; i++) - { - if (bV2Format) /* new parameter format */ - { - NDR_PARAM_OIF_BASETYPE * pParam = - (NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset]; - unsigned char * pArg; - - current_stack_offset = pParam->stack_offset; - pArg = ARG_FROM_OFFSET(args, current_stack_offset); - - TRACE("param[%d]: new format\n", i); - TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n"); - TRACE("\tstack_offset: 0x%x\n", current_stack_offset); - TRACE("\tmemory addr (before): %p\n", pArg); - - if (pParam->param_attributes.IsBasetype) - { - const unsigned char * pTypeFormat = - &pParam->type_format_char; - - if (pParam->param_attributes.IsSimpleRef) - pArg = *(unsigned char **)pArg; - - TRACE("\tbase type: 0x%02x\n", *pTypeFormat); - - switch (phase) - { - case PROXY_CALCSIZE: - if (pParam->param_attributes.IsIn) - call_buffer_sizer(&stubMsg, pArg, pTypeFormat); - break; - case PROXY_MARSHAL: - if (pParam->param_attributes.IsIn) - call_marshaller(&stubMsg, pArg, pTypeFormat); - break; - case PROXY_UNMARSHAL: - if (pParam->param_attributes.IsOut) - { - unsigned char *pRetVal = (unsigned char *)&RetVal; - if (pParam->param_attributes.IsReturn) - call_unmarshaller(&stubMsg, &pRetVal, pTypeFormat, 0); - else - call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); - TRACE("pRetVal = %p\n", pRetVal); - } - break; - default: - RpcRaiseException(RPC_S_INTERNAL_ERROR); - } - - current_offset += sizeof(NDR_PARAM_OIF_BASETYPE); - } - else - { - NDR_PARAM_OIF_OTHER * pParamOther = - (NDR_PARAM_OIF_OTHER *)&pFormat[current_offset]; - - const unsigned char * pTypeFormat = - &(pStubDesc->pFormatTypes[pParamOther->type_offset]); - - /* if a simple ref pointer then we have to do the - * check for the pointer being non-NULL. */ - if (pParam->param_attributes.IsSimpleRef) - { - if (!*(unsigned char **)pArg) - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - - TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat); - - switch (phase) - { - case PROXY_CALCSIZE: - if (pParam->param_attributes.IsIn) - { - if (pParam->param_attributes.IsByValue) - call_buffer_sizer(&stubMsg, pArg, pTypeFormat); - else - call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); - } - break; - case PROXY_MARSHAL: - if (pParam->param_attributes.IsIn) - { - if (pParam->param_attributes.IsByValue) - call_marshaller(&stubMsg, pArg, pTypeFormat); - else - call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); - } - break; - case PROXY_UNMARSHAL: - if (pParam->param_attributes.IsOut) - { - unsigned char *pRetVal = (unsigned char *)&RetVal; - if (pParam->param_attributes.IsReturn) - call_unmarshaller(&stubMsg, &pRetVal, pTypeFormat, 0); - else if (pParam->param_attributes.IsByValue) - call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); - else - call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); - } - break; - default: - RpcRaiseException(RPC_S_INTERNAL_ERROR); - } - - current_offset += sizeof(NDR_PARAM_OIF_OTHER); - } - TRACE("\tmemory addr (after): %p\n", pArg); - } - else /* old parameter format */ - { - NDR_PARAM_OI_BASETYPE * pParam = - (NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset]; - unsigned char * pArg = ARG_FROM_OFFSET(args, current_stack_offset); - - /* no more parameters; exit loop */ - if (current_stack_offset > stack_size) - break; - - TRACE("param[%d]: old format\n", i); - TRACE("\tparam_direction: %x\n", pParam->param_direction); - TRACE("\tstack_offset: 0x%x\n", current_stack_offset); - TRACE("\tmemory addr (before): %p\n", pArg); - - if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE || - pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) - { - const unsigned char * pTypeFormat = - &pParam->type_format_char; - - TRACE("\tbase type 0x%02x\n", *pTypeFormat); - - switch (phase) - { - case PROXY_CALCSIZE: - if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) - call_buffer_sizer(&stubMsg, pArg, pTypeFormat); - break; - case PROXY_MARSHAL: - if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) - call_marshaller(&stubMsg, pArg, pTypeFormat); - break; - case PROXY_UNMARSHAL: - if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) - { - if (pParam->param_direction & RPC_FC_RETURN_PARAM) - call_unmarshaller(&stubMsg, (unsigned char **)&RetVal, pTypeFormat, 0); - else - call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); - } - break; - default: - RpcRaiseException(RPC_S_INTERNAL_ERROR); - } - - current_stack_offset += call_memory_sizer(&stubMsg, pTypeFormat); - current_offset += sizeof(NDR_PARAM_OI_BASETYPE); - } - else - { - NDR_PARAM_OI_OTHER * pParamOther = - (NDR_PARAM_OI_OTHER *)&pFormat[current_offset]; - - const unsigned char *pTypeFormat = - &pStubDesc->pFormatTypes[pParamOther->type_offset]; - - TRACE("\tcomplex type 0x%02x\n", *pTypeFormat); - - switch (phase) - { - case PROXY_CALCSIZE: - if (pParam->param_direction == RPC_FC_IN_PARAM || - pParam->param_direction & RPC_FC_IN_OUT_PARAM) - call_buffer_sizer(&stubMsg, pArg, pTypeFormat); - break; - case PROXY_MARSHAL: - if (pParam->param_direction == RPC_FC_IN_PARAM || - pParam->param_direction & RPC_FC_IN_OUT_PARAM) - call_marshaller(&stubMsg, pArg, pTypeFormat); - break; - case PROXY_UNMARSHAL: - if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || - pParam->param_direction == RPC_FC_OUT_PARAM) - call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); - else if (pParam->param_direction == RPC_FC_RETURN_PARAM) - call_unmarshaller(&stubMsg, (unsigned char **)&RetVal, pTypeFormat, 0); - break; - default: - RpcRaiseException(RPC_S_INTERNAL_ERROR); - } - - current_stack_offset += pParamOther->stack_size * sizeof(INT); - current_offset += sizeof(NDR_PARAM_OI_OTHER); - } - TRACE("\tmemory addr (after): %p\n", pArg); - } - } - + if (bV2Format) + client_do_args(&stubMsg, pFormat, phase, number_of_params, + (unsigned char *)&RetVal); + else + client_do_args_old_format(&stubMsg, pFormat, phase, stack_size, + (unsigned char *)&RetVal, + (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)); break; default: ERR("shouldn't reach here. phase %d\n", phase); @@ -884,30 +958,29 @@ LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pForma } } - /* FIXME: unbind the binding handle */ - - if (ext_flags & RPC_FC_PROC_EXT_NEWCORRDESC) + if (ext_flags.HasNewCorrDesc) { /* free extra correlation package */ /* NdrCorrelationFree(&stubMsg); */ } - if (Oif_flags & RPC_FC_PROC_OI2F_HASPIPES) + if (Oif_flags.HasPipes) { /* NdrPipesDone(...) */ } -#if 0 /* free the full pointer translation tables */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables); -#endif /* free marshalling buffer */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) NdrProxyFreeBuffer(This, &stubMsg); else + { NdrFreeBuffer(&stubMsg); + client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding); + } TRACE("RetVal = 0x%lx\n", RetVal); @@ -936,9 +1009,9 @@ __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigne rep movsd ; Copy dword blocks call [ebp+8] ; Call function lea esp, [ebp-8] ; Restore stack - pop ebp ; Restore registers - pop esi + pop esi ; Restore registers pop edi + pop ebp ret } } @@ -951,7 +1024,7 @@ __ASM_GLOBAL_FUNC(call_server_func, "pushl %esi\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 MacOS X */ + "andl $~15, %esp\n\t" /* Make sure stack has 16-byte alignment for Mac OS X */ "movl %esp, %edi\n\t" "movl %eax, %ecx\n\t" "movl 12(%ebp), %esi\n\t" @@ -963,7 +1036,7 @@ __ASM_GLOBAL_FUNC(call_server_func, "popl %esi\n\t" /* Restore registers */ "popl %edi\n\t" "popl %ebp\n\t" - "ret\n" ); + "ret\n" ) #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) @@ -973,12 +1046,41 @@ LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, uns } #endif +static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +{ + DWORD size; + switch(*pFormat) + { + case RPC_FC_STRUCT: + size = *(const WORD*)(pFormat + 2); + break; + case RPC_FC_CARRAY: + size = *(const WORD*)(pFormat + 2); + ComputeConformance(pStubMsg, NULL, pFormat + 4, 0); + size *= pStubMsg->MaxCount; + break; + case RPC_FC_SMFARRAY: + size = *(const WORD*)(pFormat + 2); + break; + case RPC_FC_LGFARRAY: + size = *(const DWORD*)(pFormat + 2); + break; + default: + FIXME("Unhandled type %02x\n", *pFormat); + /* fallthrough */ + case RPC_FC_RP: + size = sizeof(void *); + break; + } + return size; +} + /* FIXME: need to free some stuff in here too */ -long WINAPI NdrStubCall2( +LONG WINAPI NdrStubCall2( struct IRpcStubBuffer * pThis, struct IRpcChannelBuffer * pChannel, PRPC_MESSAGE pRpcMsg, - unsigned long * pdwStubPhase) + DWORD * pdwStubPhase) { const MIDL_SERVER_INFO *pServerInfo; const MIDL_STUB_DESC *pStubDesc; @@ -995,9 +1097,9 @@ long WINAPI NdrStubCall2( /* counter */ unsigned short i; /* cache of Oif_flags from v2 procedure header */ - unsigned char Oif_flags = 0; - /* cache of extension flags from NDR_PROC_EXTENSION */ - unsigned char ext_flags = 0; + 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 */ @@ -1008,9 +1110,8 @@ long WINAPI NdrStubCall2( int current_offset; /* -Oif or -Oicf generated format */ BOOL bV2Format = FALSE; - /* the return value (not from this function, but to be put back onto - * the wire */ - LONG_PTR RetVal = 0; + /* location to put retval into */ + LONG_PTR *retval_ptr = NULL; TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase); @@ -1026,13 +1127,17 @@ long WINAPI NdrStubCall2( /* Later NDR language versions probably won't be backwards compatible */ if (pStubDesc->Version > 0x50002) { - FIXME("Incompatible stub description version: 0x%lx\n", pStubDesc->Version); + FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version); RpcRaiseException(RPC_X_WRONG_STUB_VERSION); } + /* create the full pointer translation tables, if requested */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER); + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) { - NDR_PROC_HEADER_RPC * pProcHeader = (NDR_PROC_HEADER_RPC *)&pFormat[0]; + const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0]; stack_size = pProcHeader->stack_size; current_offset = sizeof(NDR_PROC_HEADER_RPC); @@ -1080,23 +1185,23 @@ long WINAPI NdrStubCall2( if (bV2Format) { - NDR_PROC_PARTIAL_OIF_HEADER * pOIFHeader = - (NDR_PROC_PARTIAL_OIF_HEADER*)&pFormat[current_offset]; + const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = + (const NDR_PROC_PARTIAL_OIF_HEADER *)&pFormat[current_offset]; - Oif_flags = pOIFHeader->Oif_flags; + Oif_flags = pOIFHeader->Oi2Flags; number_of_params = pOIFHeader->number_of_params; current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER); } - TRACE("Oif_flags = 0x%02x\n", Oif_flags); + TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags); - if (Oif_flags & RPC_FC_PROC_OI2F_HASEXTS) + if (Oif_flags.HasExtensions) { - NDR_PROC_EXTENSION * pExtensions = - (NDR_PROC_EXTENSION *)&pFormat[current_offset]; - ext_flags = pExtensions->ext_flags; - current_offset += pExtensions->extension_version; + const NDR_PROC_HEADER_EXTS *pExtensions = + (const NDR_PROC_HEADER_EXTS *)&pFormat[current_offset]; + ext_flags = pExtensions->Flags2; + current_offset += pExtensions->Size; } if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) @@ -1104,17 +1209,9 @@ long WINAPI NdrStubCall2( else NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc); - /* create the full pointer translation tables, if requested */ - if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) -#if 0 - stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER); -#else - FIXME("initialize full pointer translation tables\n"); -#endif - /* store the RPC flags away */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) - pRpcMsg->RpcFlags = ((NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; + pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; /* use alternate memory allocation routines */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC) @@ -1124,21 +1221,20 @@ long WINAPI NdrStubCall2( FIXME("Set RPCSS memory allocation routines\n"); #endif - if (Oif_flags & RPC_FC_PROC_OI2F_HASPIPES) + 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 & RPC_FC_PROC_EXT_NEWCORRDESC) + if (ext_flags.HasNewCorrDesc) { /* initialize extra correlation package */ FIXME("new correlation description not implemented\n"); stubMsg.fHasNewCorrDesc = TRUE; } - /* convert strings, floating point values and endianess into our * preferred format */ if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION) @@ -1148,8 +1244,8 @@ long WINAPI NdrStubCall2( TRACE("allocating memory for stack of size %x\n", stack_size); - args = HeapAlloc(GetProcessHeap(), 0, stack_size); - ZeroMemory(args, stack_size); + args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size); + stubMsg.StackTop = args; /* used by conformance of top-level objects */ /* add the implicit This pointer as the first arg to the function if we * are calling an object method */ @@ -1170,21 +1266,32 @@ long WINAPI NdrStubCall2( { case STUBLESS_CALLSERVER: /* call the server function */ - if (pServerInfo->ThunkTable) - { - stubMsg.StackTop = args; + if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum]) pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg); - /* FIXME: RetVal is stored as the last argument - retrieve it */ - } - else if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) - { - SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject; - RetVal = call_server_func(vtbl[pRpcMsg->ProcNum], args, stack_size); - } else - RetVal = call_server_func(pServerInfo->DispatchTable[pRpcMsg->ProcNum], args, stack_size); + { + SERVER_ROUTINE func; + LONG_PTR retval; - TRACE("stub implementation returned %p\n", (void *)RetVal); + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject; + func = vtbl[pRpcMsg->ProcNum]; + } + else + func = pServerInfo->DispatchTable[pRpcMsg->ProcNum]; + + /* FIXME: what happens with return values that don't fit into a single register on x86? */ + retval = call_server_func(func, args, stack_size); + + if (retval_ptr) + { + TRACE("stub implementation returned 0x%lx\n", retval); + *retval_ptr = retval; + } + else + TRACE("void stub implementation\n"); + } stubMsg.Buffer = NULL; stubMsg.BufferLength = 0; @@ -1222,7 +1329,7 @@ long WINAPI NdrStubCall2( if (bV2Format) /* new parameter format */ { const NDR_PARAM_OIF_BASETYPE *pParam = - (NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset]; + (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset]; unsigned char *pArg; current_stack_offset = pParam->stack_offset; @@ -1230,7 +1337,7 @@ long WINAPI NdrStubCall2( TRACE("param[%d]: new format\n", i); TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n"); - TRACE("\tstack_offset: %x\n", current_stack_offset); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset); TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg); if (pParam->param_attributes.ServerAllocSize) @@ -1247,9 +1354,7 @@ long WINAPI NdrStubCall2( switch (phase) { case STUBLESS_MARSHAL: - if (pParam->param_attributes.IsReturn) - call_marshaller(&stubMsg, (unsigned char *)&RetVal, pTypeFormat); - else if (pParam->param_attributes.IsOut) + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) { if (pParam->param_attributes.IsSimpleRef) call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); @@ -1266,11 +1371,14 @@ long WINAPI NdrStubCall2( else call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); } + + /* make a note of the address of the return value parameter for later */ + if (pParam->param_attributes.IsReturn) + retval_ptr = (LONG_PTR *)pArg; + break; case STUBLESS_CALCSIZE: - if (pParam->param_attributes.IsReturn) - call_buffer_sizer(&stubMsg, (unsigned char *)&RetVal, pTypeFormat); - else if (pParam->param_attributes.IsOut) + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) { if (pParam->param_attributes.IsSimpleRef) call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); @@ -1286,8 +1394,8 @@ long WINAPI NdrStubCall2( } else { - NDR_PARAM_OIF_OTHER * pParamOther = - (NDR_PARAM_OIF_OTHER *)&pFormat[current_offset]; + const NDR_PARAM_OIF_OTHER *pParamOther = + (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset]; const unsigned char * pTypeFormat = &(pStubDesc->pFormatTypes[pParamOther->type_offset]); @@ -1297,9 +1405,7 @@ long WINAPI NdrStubCall2( switch (phase) { case STUBLESS_MARSHAL: - if (pParam->param_attributes.IsReturn) - call_marshaller(&stubMsg, (unsigned char *)&RetVal, pTypeFormat); - else if (pParam->param_attributes.IsOut) + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) { if (pParam->param_attributes.IsByValue) call_marshaller(&stubMsg, pArg, pTypeFormat); @@ -1319,17 +1425,20 @@ long WINAPI NdrStubCall2( else call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); } - else if ((pParam->param_attributes.IsOut) && - !(pParam->param_attributes.IsByValue)) + else if (pParam->param_attributes.IsOut && + !pParam->param_attributes.IsByValue) { - *(void **)pArg = NdrAllocate(&stubMsg, sizeof(void *)); - **(void ***)pArg = 0; + DWORD size = calc_arg_size(&stubMsg, pTypeFormat); + + if(size) + { + *(void **)pArg = NdrAllocate(&stubMsg, size); + memset(*(void **)pArg, 0, size); + } } break; case STUBLESS_CALCSIZE: - if (pParam->param_attributes.IsReturn) - call_buffer_sizer(&stubMsg, (unsigned char *)&RetVal, pTypeFormat); - else if (pParam->param_attributes.IsOut) + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) { if (pParam->param_attributes.IsByValue) call_buffer_sizer(&stubMsg, pArg, pTypeFormat); @@ -1347,15 +1456,21 @@ long WINAPI NdrStubCall2( } else /* old parameter format */ { - NDR_PARAM_OI_BASETYPE *pParam = - (NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset]; - unsigned char *pArg = (unsigned char *)(args+current_stack_offset); + const NDR_PARAM_OI_BASETYPE *pParam = + (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset]; + /* note: current_stack_offset starts after the This pointer + * if present, so adjust this */ + unsigned short current_stack_offset_adjusted = current_stack_offset + + ((pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) ? sizeof(void *) : 0); + unsigned char *pArg = (unsigned char *)(args+current_stack_offset_adjusted); /* no more parameters; exit loop */ - if (current_stack_offset > stack_size) + if (current_stack_offset_adjusted >= stack_size) break; - TRACE("param[%d]: old format\n\tparam_direction: 0x%x\n", i, pParam->param_direction); + TRACE("param[%d]: old format\n", i); + TRACE("\tparam_direction: 0x%x\n", pParam->param_direction); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted); if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE || pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) @@ -1369,21 +1484,17 @@ long WINAPI NdrStubCall2( { case STUBLESS_MARSHAL: if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) - { - unsigned char *pRetVal = (unsigned char *)&RetVal; - call_marshaller(&stubMsg, (unsigned char *)&pRetVal, pTypeFormat); - } + call_marshaller(&stubMsg, pArg, pTypeFormat); break; case STUBLESS_UNMARSHAL: if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); + else if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + retval_ptr = (LONG_PTR *)pArg; break; case STUBLESS_CALCSIZE: if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) - { - unsigned char * pRetVal = (unsigned char *)&RetVal; - call_buffer_sizer(&stubMsg, (unsigned char *)&pRetVal, pTypeFormat); - } + call_buffer_sizer(&stubMsg, pArg, pTypeFormat); break; default: RpcRaiseException(RPC_S_INTERNAL_ERROR); @@ -1394,8 +1505,8 @@ long WINAPI NdrStubCall2( } else { - NDR_PARAM_OI_OTHER * pParamOther = - (NDR_PARAM_OI_OTHER *)&pFormat[current_offset]; + const NDR_PARAM_OI_OTHER *pParamOther = + (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset]; const unsigned char * pTypeFormat = &pStubDesc->pFormatTypes[pParamOther->type_offset]; @@ -1405,29 +1516,33 @@ long WINAPI NdrStubCall2( switch (phase) { case STUBLESS_MARSHAL: - if (pParam->param_direction == RPC_FC_RETURN_PARAM) - { - unsigned char *pRetVal = (unsigned char *)&RetVal; - call_marshaller(&stubMsg, (unsigned char *)&pRetVal, pTypeFormat); - } - else if (pParam->param_direction == RPC_FC_OUT_PARAM || - pParam->param_direction == RPC_FC_IN_OUT_PARAM) - call_marshaller(&stubMsg, pArg, pTypeFormat); + if (pParam->param_direction == RPC_FC_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_RETURN_PARAM) + call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); break; case STUBLESS_UNMARSHAL: if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || pParam->param_direction == RPC_FC_IN_PARAM) - call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); + call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); + else if (pParam->param_direction == RPC_FC_RETURN_PARAM) + retval_ptr = (LONG_PTR *)pArg; + else if (pParam->param_direction == RPC_FC_OUT_PARAM) + { + DWORD size = calc_arg_size(&stubMsg, pTypeFormat); + + if(size) + { + *(void **)pArg = NdrAllocate(&stubMsg, size); + memset(*(void **)pArg, 0, size); + } + } break; case STUBLESS_CALCSIZE: - if (pParam->param_direction == RPC_FC_RETURN_PARAM) - { - unsigned char * pRetVal = (unsigned char *)&RetVal; - call_buffer_sizer(&stubMsg, (unsigned char *)&pRetVal, pTypeFormat); - } - else if (pParam->param_direction == RPC_FC_OUT_PARAM || - pParam->param_direction == RPC_FC_IN_OUT_PARAM) - call_buffer_sizer(&stubMsg, pArg, pTypeFormat); + if (pParam->param_direction == RPC_FC_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_RETURN_PARAM) + call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); break; default: RpcRaiseException(RPC_S_INTERNAL_ERROR); @@ -1448,22 +1563,20 @@ long WINAPI NdrStubCall2( pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer); - if (ext_flags & RPC_FC_PROC_EXT_NEWCORRDESC) + if (ext_flags.HasNewCorrDesc) { /* free extra correlation package */ /* NdrCorrelationFree(&stubMsg); */ } - if (Oif_flags & RPC_FC_PROC_OI2F_HASPIPES) + if (Oif_flags.HasPipes) { /* NdrPipesDone(...) */ } -#if 0 /* free the full pointer translation tables */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables); -#endif /* free server function stack */ HeapFree(GetProcessHeap(), 0, args); diff --git a/reactos/dll/win32/rpcrt4/rpc_binding.c b/reactos/dll/win32/rpcrt4/rpc_binding.c index 273f2253d45..ad96ac6496e 100644 --- a/reactos/dll/win32/rpcrt4/rpc_binding.c +++ b/reactos/dll/win32/rpcrt4/rpc_binding.c @@ -4,6 +4,7 @@ * Copyright 2001 Ove Kåven, TransGaming Technologies * Copyright 2003 Mike Hearn * Copyright 2004 Filip Navara + * Copyright 2006 CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,10 +18,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - a whole lot + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -59,7 +57,7 @@ LPSTR RPCRT4_strndupA(LPCSTR src, INT slen) return s; } -LPSTR RPCRT4_strdupWtoA(LPWSTR src) +LPSTR RPCRT4_strdupWtoA(LPCWSTR src) { DWORD len; LPSTR s; @@ -70,7 +68,7 @@ LPSTR RPCRT4_strdupWtoA(LPWSTR src) return s; } -LPWSTR RPCRT4_strdupAtoW(LPSTR src) +LPWSTR RPCRT4_strdupAtoW(LPCSTR src) { DWORD len; LPWSTR s; @@ -81,7 +79,7 @@ LPWSTR RPCRT4_strdupAtoW(LPSTR src) return s; } -LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen) +LPWSTR RPCRT4_strndupW(LPCWSTR src, INT slen) { DWORD len; LPWSTR s; @@ -99,219 +97,6 @@ void RPCRT4_strfree(LPSTR src) HeapFree(GetProcessHeap(), 0, src); } -RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding) -{ - RpcConnection* NewConnection; - - NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection)); - NewConnection->server = server; - NewConnection->Protseq = RPCRT4_strdupA(Protseq); - NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); - NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); - NewConnection->Used = Binding; - NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; - - TRACE("connection: %p\n", NewConnection); - *Connection = NewConnection; - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) -{ - TRACE("connection: %p\n", Connection); - - RPCRT4_CloseConnection(Connection); - RPCRT4_strfree(Connection->Endpoint); - RPCRT4_strfree(Connection->NetworkAddr); - RPCRT4_strfree(Connection->Protseq); - HeapFree(GetProcessHeap(), 0, Connection); - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection) -{ - TRACE("(Connection == ^%p)\n", Connection); - if (!Connection->conn) { - if (Connection->server) { /* server */ - /* protseq=ncalrpc: supposed to use NT LPC ports, - * but we'll implement it with named pipes for now */ - if (strcmp(Connection->Protseq, "ncalrpc") == 0) { - static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; - LPSTR pname; - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("listening on %s\n", pname); - Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) { - WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); - if (GetLastError() == ERROR_PIPE_CONNECTED) { - SetEvent(Connection->ovl[0].hEvent); - return RPC_S_OK; - } else if (GetLastError() == ERROR_IO_PENDING) { - return RPC_S_OK; - } - return RPC_S_SERVER_UNAVAILABLE; - } - } - /* protseq=ncacn_np: named pipes */ - else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { - static LPCSTR prefix = "\\\\."; - LPSTR pname; - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("listening on %s\n", pname); - Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) { - if (GetLastError() == ERROR_PIPE_CONNECTED) { - SetEvent(Connection->ovl[0].hEvent); - return RPC_S_OK; - } else if (GetLastError() == ERROR_IO_PENDING) { - return RPC_S_OK; - } - WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); - return RPC_S_SERVER_UNAVAILABLE; - } - } - else { - ERR("protseq %s not supported\n", Connection->Protseq); - return RPC_S_PROTSEQ_NOT_SUPPORTED; - } - } - else { /* client */ - /* protseq=ncalrpc: supposed to use NT LPC ports, - * but we'll implement it with named pipes for now */ - if (strcmp(Connection->Protseq, "ncalrpc") == 0) { - static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; - LPSTR pname; - HANDLE conn; - DWORD err; - DWORD dwMode; - - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("connecting to %s\n", pname); - while (TRUE) { - if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { - conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, 0); - if (conn != INVALID_HANDLE_VALUE) break; - err = GetLastError(); - if (err == ERROR_PIPE_BUSY) continue; - TRACE("connection failed, error=%lx\n", err); - HeapFree(GetProcessHeap(), 0, pname); - return RPC_S_SERVER_TOO_BUSY; - } else { - err = GetLastError(); - WARN("connection failed, error=%lx\n", err); - HeapFree(GetProcessHeap(), 0, pname); - return RPC_S_SERVER_UNAVAILABLE; - } - } - - /* success */ - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - /* pipe is connected; change to message-read mode. */ - dwMode = PIPE_READMODE_MESSAGE; - SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->conn = conn; - } - /* protseq=ncacn_np: named pipes */ - else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { - static LPCSTR prefix = "\\\\."; - LPSTR pname; - HANDLE conn; - DWORD err; - DWORD dwMode; - - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("connecting to %s\n", pname); - conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, 0); - if (conn == INVALID_HANDLE_VALUE) { - err = GetLastError(); - /* we don't need to handle ERROR_PIPE_BUSY here, - * the doc says that it is returned to the app */ - WARN("connection failed, error=%lx\n", err); - HeapFree(GetProcessHeap(), 0, pname); - if (err == ERROR_PIPE_BUSY) - return RPC_S_SERVER_TOO_BUSY; - else - return RPC_S_SERVER_UNAVAILABLE; - } - - /* success */ - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - /* pipe is connected; change to message-read mode. */ - dwMode = PIPE_READMODE_MESSAGE; - SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->conn = conn; - } else { - ERR("protseq %s not supported\n", Connection->Protseq); - return RPC_S_PROTSEQ_NOT_SUPPORTED; - } - } - } - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) -{ - TRACE("(Connection == ^%p)\n", Connection); - if (Connection->conn) { - FlushFileBuffers(Connection->conn); - CloseHandle(Connection->conn); - Connection->conn = 0; - } - if (Connection->ovl[0].hEvent) { - CloseHandle(Connection->ovl[0].hEvent); - Connection->ovl[0].hEvent = 0; - } - if (Connection->ovl[1].hEvent) { - CloseHandle(Connection->ovl[1].hEvent); - Connection->ovl[1].hEvent = 0; - } - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) -{ - RpcConnection* NewConnection; - RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq, - OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL); - if (err == RPC_S_OK) { - /* because of the way named pipes work, we'll transfer the connected pipe - * to the child, then reopen the server binding to continue listening */ - NewConnection->conn = OldConnection->conn; - NewConnection->ovl[0] = OldConnection->ovl[0]; - NewConnection->ovl[1] = OldConnection->ovl[1]; - OldConnection->conn = 0; - memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl)); - *Connection = NewConnection; - RPCRT4_OpenConnection(OldConnection); - } - return err; -} - static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server) { RpcBinding* NewBinding; @@ -325,7 +110,7 @@ static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server) return RPC_S_OK; } -RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq) +static RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPCSTR Protseq) { RpcBinding* NewBinding; @@ -338,7 +123,7 @@ RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protse return RPC_S_OK; } -RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq) +static RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPCWSTR Protseq) { RpcBinding* NewBinding; @@ -351,9 +136,12 @@ RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Prots return RPC_S_OK; } -RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions) +static RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCSTR NetworkOptions) { - TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, + RPC_STATUS status; + + TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding, debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions)); RPCRT4_strfree(Binding->NetworkAddr); @@ -364,14 +152,25 @@ RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPST } else { Binding->Endpoint = RPCRT4_strdupA(""); } + HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + Binding->NetworkOptions = RPCRT4_strdupAtoW(NetworkOptions); if (!Binding->Endpoint) ERR("out of memory?\n"); + status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + &Binding->Assoc); + if (status != RPC_S_OK) + return status; + return RPC_S_OK; } -RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions) +static RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPCWSTR NetworkAddr, + LPCWSTR Endpoint, LPCWSTR NetworkOptions) { - TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, + RPC_STATUS status; + + TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding, debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions)); RPCRT4_strfree(Binding->NetworkAddr); @@ -383,21 +182,39 @@ RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWS Binding->Endpoint = RPCRT4_strdupA(""); } if (!Binding->Endpoint) ERR("out of memory?\n"); + HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + Binding->NetworkOptions = RPCRT4_strdupW(NetworkOptions); + + status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + &Binding->Assoc); + if (status != RPC_S_OK) + return status; return RPC_S_OK; } -RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint) +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPCSTR Endpoint) { + RPC_STATUS status; + TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint); RPCRT4_strfree(Binding->Endpoint); Binding->Endpoint = RPCRT4_strdupA(Endpoint); + RpcAssoc_Release(Binding->Assoc); + Binding->Assoc = NULL; + status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + &Binding->Assoc); + if (status != RPC_S_OK) + return status; + return RPC_S_OK; } -RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid) +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, const UUID* ObjectUuid) { TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid)); if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID)); @@ -411,7 +228,7 @@ RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection) TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection); RPCRT4_AllocBinding(&NewBinding, Connection->server); - NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq); + NewBinding->Protseq = RPCRT4_strdupA(rpcrt4_conn_get_name(Connection)); NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr); NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint); NewBinding->FromConn = Connection; @@ -435,10 +252,13 @@ RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding) return RPC_S_OK; TRACE("binding: %p\n", Binding); - /* FIXME: release connections */ + if (Binding->Assoc) RpcAssoc_Release(Binding->Assoc); RPCRT4_strfree(Binding->Endpoint); RPCRT4_strfree(Binding->NetworkAddr); RPCRT4_strfree(Binding->Protseq); + HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + if (Binding->AuthInfo) RpcAuthInfo_Release(Binding->AuthInfo); + if (Binding->QOS) RpcQualityOfService_Release(Binding->QOS); HeapFree(GetProcessHeap(), 0, Binding); return RPC_S_OK; } @@ -452,15 +272,14 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, TRACE("(Binding == ^%p)\n", Binding); - /* if we try to bind a new interface and the connection is already opened, - * close the current connection and create a new with the new binding. */ - if (!Binding->server && Binding->FromConn && - memcmp(&Binding->FromConn->ActiveInterface, InterfaceId, - sizeof(RPC_SYNTAX_IDENTIFIER))) { - - TRACE("releasing pre-existing connection\n"); - RPCRT4_DestroyConnection(Binding->FromConn); - Binding->FromConn = NULL; + if (!Binding->server) { + /* try to find a compatible connection from the connection pool */ + NewConnection = RpcAssoc_GetIdleConnection(Binding->Assoc, InterfaceId, + TransferSyntax, Binding->AuthInfo, Binding->QOS); + if (NewConnection) { + *Connection = NewConnection; + return RPC_S_OK; + } } else { /* we already have a connection with acceptable binding, so use it */ if (Binding->FromConn) { @@ -470,19 +289,25 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, } /* create a new connection */ - RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding); - *Connection = NewConnection; - status = RPCRT4_OpenConnection(NewConnection); - if (status != RPC_S_OK) { + status = RPCRT4_CreateConnection(&NewConnection, Binding->server, + Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + Binding->AuthInfo, Binding->QOS, Binding); + if (status != RPC_S_OK) + return status; + + status = RPCRT4_OpenClientConnection(NewConnection); + if (status != RPC_S_OK) + { + RPCRT4_DestroyConnection(NewConnection); return status; } - + /* we need to send a binding packet if we are client. */ - if (!(*Connection)->server) { + if (!NewConnection->server) { RpcPktHdr *hdr; - DWORD count; - BYTE *response; RpcPktHdr *response_hdr; + RPC_MESSAGE msg; TRACE("sending bind request to server\n"); @@ -490,54 +315,42 @@ RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, InterfaceId, TransferSyntax); - status = RPCRT4_Send(*Connection, hdr, NULL, 0); + status = RPCRT4_Send(NewConnection, hdr, NULL, 0); + RPCRT4_FreeHeader(hdr); if (status != RPC_S_OK) { - RPCRT4_DestroyConnection(*Connection); + RPCRT4_DestroyConnection(NewConnection); return status; } - response = HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE); - if (response == NULL) { - WARN("Can't allocate memory for binding response\n"); - RPCRT4_DestroyConnection(*Connection); - return E_OUTOFMEMORY; + status = RPCRT4_Receive(NewConnection, &response_hdr, &msg); + if (status != RPC_S_OK) { + ERR("receive failed\n"); + RPCRT4_DestroyConnection(NewConnection); + return status; } - /* get a reply */ - if (!ReadFile(NewConnection->conn, response, RPC_MAX_PACKET_SIZE, &count, NULL)) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - if (count < sizeof(response_hdr->common)) { - WARN("received invalid header\n"); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - response_hdr = (RpcPktHdr*)response; - - if (response_hdr->common.rpc_ver != RPC_VER_MAJOR || - response_hdr->common.rpc_ver_minor != RPC_VER_MINOR || - response_hdr->common.ptype != PKT_BIND_ACK) { - WARN("invalid protocol version or rejection packet\n"); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - if (response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) { - WARN("server doesn't allow large enough packets\n"); - RPCRT4_DestroyConnection(*Connection); + if (response_hdr->common.ptype != PKT_BIND_ACK || + response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) { + ERR("failed to bind for interface %s, %d.%d\n", + debugstr_guid(&InterfaceId->SyntaxGUID), + InterfaceId->SyntaxVersion.MajorVersion, + InterfaceId->SyntaxVersion.MinorVersion); + RPCRT4_FreeHeader(response_hdr); + RPCRT4_DestroyConnection(NewConnection); return RPC_S_PROTOCOL_ERROR; } /* FIXME: do more checks? */ - (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; - (*Connection)->ActiveInterface = *InterfaceId; + NewConnection->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; + NewConnection->ActiveInterface = *InterfaceId; + RPCRT4_FreeHeader(response_hdr); } + if (Binding->server) + Binding->FromConn = NewConnection; + *Connection = NewConnection; + return RPC_S_OK; } @@ -545,8 +358,16 @@ RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) { TRACE("(Binding == ^%p)\n", Binding); if (!Connection) return RPC_S_OK; - if (Binding->FromConn == Connection) return RPC_S_OK; - return RPCRT4_DestroyConnection(Connection); + if (Binding->server) { + /* don't destroy a connection that is cached in the binding */ + if (Binding->FromConn == Connection) + return RPC_S_OK; + return RPCRT4_DestroyConnection(Connection); + } + else { + RpcAssoc_ReleaseIdleConnection(Binding->Assoc, Connection); + return RPC_S_OK; + } } /* utility functions for string composing and parsing */ @@ -592,49 +413,13 @@ static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src) return ndst; } -/*********************************************************************** - * RpcBindingCopy (RPCRT4.@) - */ -RPC_STATUS RPC_ENTRY RpcBindingCopy( - RPC_BINDING_HANDLE SourceBinding, - RPC_BINDING_HANDLE* DestinationBinding) -{ - TRACE("RpcBindingCopy(%p, %p) called:\n", SourceBinding, DestinationBinding); - RpcBinding *DestBinding = 0, *SrcBinding = (RpcBinding*)SourceBinding; - - if(SrcBinding->server) - { - *DestinationBinding = NULL; - return RPC_S_WRONG_KIND_OF_BINDING; - } - - DestBinding = (RpcBinding*) - HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding)); - - if(!DestBinding) - { - *DestinationBinding = NULL; - return ERROR_NOT_ENOUGH_MEMORY; - } - - memcpy(DestBinding, SrcBinding, sizeof(RpcBinding)); - DestBinding->refs = 1; - DestBinding->Next = NULL; // FIXME: ? - DestBinding->server = FALSE; - DestBinding->Protseq = RPCRT4_strndupA(SrcBinding->Protseq, -1); - DestBinding->NetworkAddr = RPCRT4_strndupA(SrcBinding->NetworkAddr, -1); - DestBinding->Endpoint = RPCRT4_strndupA(SrcBinding->Endpoint, -1); - - *DestinationBinding = DestBinding; - return RPC_S_OK; -} /*********************************************************************** * RpcStringBindingComposeA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char *Protseq, - unsigned char *NetworkAddr, unsigned char *Endpoint, - unsigned char *Options, unsigned char** StringBinding ) +RPC_STATUS WINAPI RpcStringBindingComposeA(RPC_CSTR ObjUuid, RPC_CSTR Protseq, + RPC_CSTR NetworkAddr, RPC_CSTR Endpoint, + RPC_CSTR Options, RPC_CSTR *StringBinding ) { DWORD len = 1; LPSTR data; @@ -684,12 +469,12 @@ RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char /*********************************************************************** * RpcStringBindingComposeW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq, - LPWSTR NetworkAddr, LPWSTR Endpoint, - LPWSTR Options, LPWSTR* StringBinding ) +RPC_STATUS WINAPI RpcStringBindingComposeW( RPC_WSTR ObjUuid, RPC_WSTR Protseq, + RPC_WSTR NetworkAddr, RPC_WSTR Endpoint, + RPC_WSTR Options, RPC_WSTR* StringBinding ) { DWORD len = 1; - LPWSTR data; + RPC_WSTR data; TRACE("(%s,%s,%s,%s,%s,%p)\n", debugstr_w( ObjUuid ), debugstr_w( Protseq ), @@ -737,9 +522,9 @@ RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq, /*********************************************************************** * RpcStringBindingParseA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcStringBindingParseA( unsigned char *StringBinding, unsigned char **ObjUuid, - unsigned char **Protseq, unsigned char **NetworkAddr, - unsigned char **Endpoint, unsigned char **Options) +RPC_STATUS WINAPI RpcStringBindingParseA( RPC_CSTR StringBinding, RPC_CSTR *ObjUuid, + RPC_CSTR *Protseq, RPC_CSTR *NetworkAddr, + RPC_CSTR *Endpoint, RPC_CSTR *Options) { CHAR *data, *next; static const char ep_opt[] = "endpoint="; @@ -828,9 +613,9 @@ fail: /*********************************************************************** * RpcStringBindingParseW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid, - LPWSTR *Protseq, LPWSTR *NetworkAddr, - LPWSTR *Endpoint, LPWSTR *Options) +RPC_STATUS WINAPI RpcStringBindingParseW( RPC_WSTR StringBinding, RPC_WSTR *ObjUuid, + RPC_WSTR *Protseq, RPC_WSTR *NetworkAddr, + RPC_WSTR *Endpoint, RPC_WSTR *Options) { WCHAR *data, *next; static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0}; @@ -971,11 +756,11 @@ RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectU /*********************************************************************** * RpcBindingFromStringBindingA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RPC_BINDING_HANDLE* Binding ) +RPC_STATUS WINAPI RpcBindingFromStringBindingA( RPC_CSTR StringBinding, RPC_BINDING_HANDLE* Binding ) { RPC_STATUS ret; RpcBinding* bind = NULL; - unsigned char *ObjectUuid, *Protseq, *NetworkAddr, *Endpoint, *Options; + RPC_CSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; UUID Uuid; TRACE("(%s,%p)\n", debugstr_a((char*)StringBinding), Binding); @@ -1010,11 +795,11 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RP /*********************************************************************** * RpcBindingFromStringBindingW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding ) +RPC_STATUS WINAPI RpcBindingFromStringBindingW( RPC_WSTR StringBinding, RPC_BINDING_HANDLE* Binding ) { RPC_STATUS ret; RpcBinding* bind = NULL; - LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; + RPC_WSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; UUID Uuid; TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding); @@ -1049,21 +834,21 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDIN /*********************************************************************** * RpcBindingToStringBindingA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsigned char** StringBinding ) +RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, RPC_CSTR *StringBinding ) { RPC_STATUS ret; RpcBinding* bind = (RpcBinding*)Binding; - LPSTR ObjectUuid; + RPC_CSTR ObjectUuid; TRACE("(%p,%p)\n", Binding, StringBinding); - ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid); + ret = UuidToStringA(&bind->ObjectUuid, &ObjectUuid); if (ret != RPC_S_OK) return ret; - ret = RpcStringBindingComposeA((unsigned char*) ObjectUuid, (unsigned char*)bind->Protseq, (unsigned char*) bind->NetworkAddr, + ret = RpcStringBindingComposeA(ObjectUuid, (unsigned char*)bind->Protseq, (unsigned char*) bind->NetworkAddr, (unsigned char*) bind->Endpoint, NULL, StringBinding); - RpcStringFreeA((unsigned char**)&ObjectUuid); + RpcStringFreeA(&ObjectUuid); return ret; } @@ -1071,7 +856,7 @@ RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsign /*********************************************************************** * RpcBindingToStringBindingW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, unsigned short** StringBinding ) +RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, RPC_WSTR *StringBinding ) { RPC_STATUS ret; unsigned char *str = NULL; @@ -1100,46 +885,37 @@ RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING } /*********************************************************************** - * RpcNetworkIsProtseqValidA (RPCRT4.@) + * RpcBindingCopy (RPCRT4.@) */ -RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq) { - UNICODE_STRING protseqW; +RPC_STATUS RPC_ENTRY RpcBindingCopy( + RPC_BINDING_HANDLE SourceBinding, + RPC_BINDING_HANDLE* DestinationBinding) +{ + RpcBinding *DestBinding; + RpcBinding *SrcBinding = (RpcBinding*)SourceBinding; + RPC_STATUS status; - if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ - - if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq)) { - RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); - RtlFreeUnicodeString(&protseqW); - return ret; - } else return RPC_S_OUT_OF_MEMORY; -} + TRACE("(%p, %p)\n", SourceBinding, DestinationBinding); -/*********************************************************************** - * RpcNetworkIsProtseqValidW (RPCRT4.@) - * - * Checks if the given protocol sequence is known by the RPC system. - * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. - * - * We currently support: - * ncalrpc local-only rpc over LPC (LPC is not really used) - * ncacn_np rpc over named pipes - */ -RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq) { - static const WCHAR protseqsW[][15] = { - {'n','c','a','l','r','p','c',0}, - {'n','c','a','c','n','_','n','p',0} - }; - static const int count = sizeof(protseqsW) / sizeof(protseqsW[0]); - int i; + status = RPCRT4_AllocBinding(&DestBinding, SrcBinding->server); + if (status != RPC_S_OK) return status; - if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ + DestBinding->ObjectUuid = SrcBinding->ObjectUuid; + DestBinding->BlockingFn = SrcBinding->BlockingFn; + DestBinding->Protseq = RPCRT4_strndupA(SrcBinding->Protseq, -1); + DestBinding->NetworkAddr = RPCRT4_strndupA(SrcBinding->NetworkAddr, -1); + DestBinding->Endpoint = RPCRT4_strndupA(SrcBinding->Endpoint, -1); + DestBinding->NetworkOptions = RPCRT4_strdupW(SrcBinding->NetworkOptions); + if (SrcBinding->Assoc) SrcBinding->Assoc->refs++; + DestBinding->Assoc = SrcBinding->Assoc; - for (i = 0; i < count; i++) { - if (!strcmpW(protseq, protseqsW[i])) return RPC_S_OK; - } - - FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq)); - return RPC_S_PROTSEQ_NOT_SUPPORTED; + if (SrcBinding->AuthInfo) RpcAuthInfo_AddRef(SrcBinding->AuthInfo); + DestBinding->AuthInfo = SrcBinding->AuthInfo; + if (SrcBinding->QOS) RpcQualityOfService_AddRef(SrcBinding->QOS); + DestBinding->QOS = SrcBinding->QOS; + + *DestinationBinding = DestBinding; + return RPC_S_OK; } /*********************************************************************** @@ -1191,6 +967,182 @@ RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle) return RPC_S_OK; } +static RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc, + CredHandle cred, TimeStamp exp, + ULONG cbMaxToken, RpcAuthInfo **ret) +{ + RpcAuthInfo *AuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo)); + if (!AuthInfo) + return ERROR_OUTOFMEMORY; + + AuthInfo->refs = 1; + AuthInfo->AuthnLevel = AuthnLevel; + AuthInfo->AuthnSvc = AuthnSvc; + AuthInfo->cred = cred; + AuthInfo->exp = exp; + AuthInfo->cbMaxToken = cbMaxToken; + *ret = AuthInfo; + return RPC_S_OK; +} + +ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo) +{ + return InterlockedIncrement(&AuthInfo->refs); +} + +ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo) +{ + ULONG refs = InterlockedDecrement(&AuthInfo->refs); + + if (!refs) + { + FreeCredentialsHandle(&AuthInfo->cred); + HeapFree(GetProcessHeap(), 0, AuthInfo); + } + + return refs; +} + +static RPC_STATUS RpcQualityOfService_Create(const RPC_SECURITY_QOS *qos_src, BOOL unicode, RpcQualityOfService **qos_dst) +{ + RpcQualityOfService *qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos)); + + if (!qos) + return RPC_S_OUT_OF_RESOURCES; + + qos->refs = 1; + qos->qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos->qos)); + if (!qos->qos) goto error; + qos->qos->Version = qos_src->Version; + qos->qos->Capabilities = qos_src->Capabilities; + qos->qos->IdentityTracking = qos_src->IdentityTracking; + qos->qos->ImpersonationType = qos_src->ImpersonationType; + qos->qos->AdditionalSecurityInfoType = 0; + + if (qos_src->Version >= 2) + { + const RPC_SECURITY_QOS_V2_W *qos_src2 = (const RPC_SECURITY_QOS_V2_W *)qos_src; + qos->qos->AdditionalSecurityInfoType = qos_src2->AdditionalSecurityInfoType; + if (qos_src2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_src = qos_src2->u.HttpCredentials; + RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_dst; + + http_credentials_dst = HeapAlloc(GetProcessHeap(), 0, sizeof(*http_credentials_dst)); + qos->qos->u.HttpCredentials = http_credentials_dst; + if (!http_credentials_dst) goto error; + http_credentials_dst->TransportCredentials = NULL; + http_credentials_dst->Flags = http_credentials_src->Flags; + http_credentials_dst->AuthenticationTarget = http_credentials_src->AuthenticationTarget; + http_credentials_dst->NumberOfAuthnSchemes = http_credentials_src->NumberOfAuthnSchemes; + http_credentials_dst->AuthnSchemes = NULL; + http_credentials_dst->ServerCertificateSubject = NULL; + if (http_credentials_src->TransportCredentials) + { + SEC_WINNT_AUTH_IDENTITY_W *cred_dst; + cred_dst = http_credentials_dst->TransportCredentials = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cred_dst)); + if (!cred_dst) goto error; + cred_dst->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + if (unicode) + { + const SEC_WINNT_AUTH_IDENTITY_W *cred_src = http_credentials_src->TransportCredentials; + cred_dst->UserLength = cred_src->UserLength; + cred_dst->PasswordLength = cred_src->PasswordLength; + cred_dst->DomainLength = cred_src->DomainLength; + cred_dst->User = RPCRT4_strndupW(cred_src->User, cred_src->UserLength); + cred_dst->Password = RPCRT4_strndupW(cred_src->Password, cred_src->PasswordLength); + cred_dst->Domain = RPCRT4_strndupW(cred_src->Domain, cred_src->DomainLength); + } + else + { + const SEC_WINNT_AUTH_IDENTITY_A *cred_src = (const SEC_WINNT_AUTH_IDENTITY_A *)http_credentials_src->TransportCredentials; + cred_dst->UserLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, NULL, 0); + cred_dst->DomainLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, NULL, 0); + cred_dst->PasswordLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, NULL, 0); + cred_dst->User = HeapAlloc(GetProcessHeap(), 0, cred_dst->UserLength * sizeof(WCHAR)); + cred_dst->Password = HeapAlloc(GetProcessHeap(), 0, cred_dst->PasswordLength * sizeof(WCHAR)); + cred_dst->Domain = HeapAlloc(GetProcessHeap(), 0, cred_dst->DomainLength * sizeof(WCHAR)); + if (!cred_dst || !cred_dst->Password || !cred_dst->Domain) goto error; + MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, cred_dst->User, cred_dst->UserLength); + MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, cred_dst->Domain, cred_dst->DomainLength); + MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, cred_dst->Password, cred_dst->PasswordLength); + } + } + if (http_credentials_src->NumberOfAuthnSchemes) + { + http_credentials_dst->AuthnSchemes = HeapAlloc(GetProcessHeap(), 0, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes)); + if (!http_credentials_dst->AuthnSchemes) goto error; + memcpy(http_credentials_dst->AuthnSchemes, http_credentials_src->AuthnSchemes, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes)); + } + if (http_credentials_src->ServerCertificateSubject) + { + if (unicode) + http_credentials_dst->ServerCertificateSubject = + RPCRT4_strndupW(http_credentials_src->ServerCertificateSubject, + strlenW(http_credentials_src->ServerCertificateSubject)); + else + http_credentials_dst->ServerCertificateSubject = + RPCRT4_strdupAtoW((char *)http_credentials_src->ServerCertificateSubject); + if (!http_credentials_dst->ServerCertificateSubject) goto error; + } + } + } + *qos_dst = qos; + return RPC_S_OK; + +error: + if (qos->qos) + { + if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP && + qos->qos->u.HttpCredentials) + { + if (qos->qos->u.HttpCredentials->TransportCredentials) + { + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos); + } + HeapFree(GetProcessHeap(), 0, qos); + return RPC_S_OUT_OF_RESOURCES; +} + +ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos) +{ + return InterlockedIncrement(&qos->refs); +} + +ULONG RpcQualityOfService_Release(RpcQualityOfService *qos) +{ + ULONG refs = InterlockedDecrement(&qos->refs); + + if (!refs) + { + if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + if (qos->qos->u.HttpCredentials->TransportCredentials) + { + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos); + HeapFree(GetProcessHeap(), 0, qos); + } + return refs; +} + /*********************************************************************** * RpcRevertToSelf (RPCRT4.@) */ @@ -1200,3 +1152,328 @@ RPC_STATUS WINAPI RpcRevertToSelf(void) RevertToSelf(); return RPC_S_OK; } + +/*********************************************************************** + * RpcMgmtSetComTimeout (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtSetComTimeout(RPC_BINDING_HANDLE BindingHandle, unsigned int Timeout) +{ + FIXME("(%p, %d): stub\n", BindingHandle, Timeout); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoExA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc, + ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS ) +{ + FIXME("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoExW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc, + ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS ) +{ + FIXME("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc ) +{ + FIXME("%p %p %p %p %p %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc ) +{ + FIXME("%p %p %p %p %p %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingSetAuthInfoExA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, + ULONG AuthnLevel, ULONG AuthnSvc, + RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr, + RPC_SECURITY_QOS *SecurityQos ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + SECURITY_STATUS r; + CredHandle cred; + TimeStamp exp; + ULONG package_count; + ULONG i; + PSecPkgInfoA packages; + ULONG cbMaxToken; + + TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_a((const char*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + + if (SecurityQos) + { + RPC_STATUS status; + + TRACE("SecurityQos { Version=%ld, Capabilties=0x%lx, IdentityTracking=%ld, ImpersonationLevel=%ld", + SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType); + if (SecurityQos->Version >= 2) + { + const RPC_SECURITY_QOS_V2_A *SecurityQos2 = (const RPC_SECURITY_QOS_V2_A *)SecurityQos; + TRACE(", AdditionalSecurityInfoType=%ld", SecurityQos2->AdditionalSecurityInfoType); + if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + TRACE(", { %p, 0x%lx, %ld, %ld, %p, %s }", + SecurityQos2->u.HttpCredentials->TransportCredentials, + SecurityQos2->u.HttpCredentials->Flags, + SecurityQos2->u.HttpCredentials->AuthenticationTarget, + SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes, + SecurityQos2->u.HttpCredentials->AuthnSchemes, + SecurityQos2->u.HttpCredentials->ServerCertificateSubject); + } + TRACE("}\n"); + status = RpcQualityOfService_Create(SecurityQos, FALSE, &bind->QOS); + if (status != RPC_S_OK) + return status; + } + else + { + if (bind->QOS) RpcQualityOfService_Release(bind->QOS); + bind->QOS = NULL; + } + + if (AuthnSvc == RPC_C_AUTHN_DEFAULT) + AuthnSvc = RPC_C_AUTHN_WINNT; + + /* FIXME: the mapping should probably be retrieved using SSPI somehow */ + if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT) + AuthnLevel = RPC_C_AUTHN_LEVEL_NONE; + + if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE)) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + return RPC_S_OK; + } + + if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + { + FIXME("unknown AuthnLevel %u\n", AuthnLevel); + return RPC_S_UNKNOWN_AUTHN_LEVEL; + } + + if (AuthzSvr) + { + FIXME("unsupported AuthzSvr %u\n", AuthzSvr); + return RPC_S_UNKNOWN_AUTHZ_SERVICE; + } + + r = EnumerateSecurityPackagesA(&package_count, &packages); + if (r != SEC_E_OK) + { + ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } + + for (i = 0; i < package_count; i++) + if (packages[i].wRPCID == AuthnSvc) + break; + + if (i == package_count) + { + FIXME("unsupported AuthnSvc %u\n", AuthnSvc); + FreeContextBuffer(packages); + return RPC_S_UNKNOWN_AUTHN_SERVICE; + } + + TRACE("found package %s for service %u\n", packages[i].Name, AuthnSvc); + r = AcquireCredentialsHandleA((SEC_CHAR *)ServerPrincName, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL, + AuthIdentity, NULL, NULL, &cred, &exp); + cbMaxToken = packages[i].cbMaxToken; + FreeContextBuffer(packages); + if (r == ERROR_SUCCESS) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken, + &bind->AuthInfo); + if (r != RPC_S_OK) + FreeCredentialsHandle(&cred); + return RPC_S_OK; + } + else + { + ERR("AcquireCredentialsHandleA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } +} + +/*********************************************************************** + * RpcBindingSetAuthInfoExW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel, + ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr, + RPC_SECURITY_QOS *SecurityQos ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + SECURITY_STATUS r; + CredHandle cred; + TimeStamp exp; + ULONG package_count; + ULONG i; + PSecPkgInfoW packages; + ULONG cbMaxToken; + + TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + + if (SecurityQos) + { + RPC_STATUS status; + + TRACE("SecurityQos { Version=%ld, Capabilties=0x%lx, IdentityTracking=%ld, ImpersonationLevel=%ld", + SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType); + if (SecurityQos->Version >= 2) + { + const RPC_SECURITY_QOS_V2_W *SecurityQos2 = (const RPC_SECURITY_QOS_V2_W *)SecurityQos; + TRACE(", AdditionalSecurityInfoType=%ld", SecurityQos2->AdditionalSecurityInfoType); + if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + TRACE(", { %p, 0x%lx, %ld, %ld, %p, %s }", + SecurityQos2->u.HttpCredentials->TransportCredentials, + SecurityQos2->u.HttpCredentials->Flags, + SecurityQos2->u.HttpCredentials->AuthenticationTarget, + SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes, + SecurityQos2->u.HttpCredentials->AuthnSchemes, + debugstr_w(SecurityQos2->u.HttpCredentials->ServerCertificateSubject)); + } + TRACE("}\n"); + status = RpcQualityOfService_Create(SecurityQos, TRUE, &bind->QOS); + if (status != RPC_S_OK) + return status; + } + else + { + if (bind->QOS) RpcQualityOfService_Release(bind->QOS); + bind->QOS = NULL; + } + + if (AuthnSvc == RPC_C_AUTHN_DEFAULT) + AuthnSvc = RPC_C_AUTHN_WINNT; + + /* FIXME: the mapping should probably be retrieved using SSPI somehow */ + if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT) + AuthnLevel = RPC_C_AUTHN_LEVEL_NONE; + + if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE)) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + return RPC_S_OK; + } + + if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + { + FIXME("unknown AuthnLevel %u\n", AuthnLevel); + return RPC_S_UNKNOWN_AUTHN_LEVEL; + } + + if (AuthzSvr) + { + FIXME("unsupported AuthzSvr %u\n", AuthzSvr); + return RPC_S_UNKNOWN_AUTHZ_SERVICE; + } + + r = EnumerateSecurityPackagesW(&package_count, &packages); + if (r != SEC_E_OK) + { + ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } + + for (i = 0; i < package_count; i++) + if (packages[i].wRPCID == AuthnSvc) + break; + + if (i == package_count) + { + FIXME("unsupported AuthnSvc %u\n", AuthnSvc); + FreeContextBuffer(packages); + return RPC_S_UNKNOWN_AUTHN_SERVICE; + } + + TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name), AuthnSvc); + r = AcquireCredentialsHandleW((SEC_WCHAR *)ServerPrincName, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL, + AuthIdentity, NULL, NULL, &cred, &exp); + cbMaxToken = packages[i].cbMaxToken; + FreeContextBuffer(packages); + if (r == ERROR_SUCCESS) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken, + &bind->AuthInfo); + if (r != RPC_S_OK) + FreeCredentialsHandle(&cred); + return RPC_S_OK; + } + else + { + ERR("AcquireCredentialsHandleA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } +} + +/*********************************************************************** + * RpcBindingSetAuthInfoA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, ULONG AuthnLevel, + ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr ) +{ + TRACE("%p %s %u %u %p %u\n", Binding, debugstr_a((const char*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr); + return RpcBindingSetAuthInfoExA(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL); +} + +/*********************************************************************** + * RpcBindingSetAuthInfoW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel, + ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr ) +{ + TRACE("%p %s %u %u %p %u\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr); + return RpcBindingSetAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL); +} + +/*********************************************************************** + * RpcBindingSetOption (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG OptionValue) +{ + FIXME("(%p, %d, %d): stub\n", BindingHandle, Option, OptionValue); + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4/rpc_binding.h b/reactos/dll/win32/rpcrt4/rpc_binding.h index e0f39aad4ed..6dde2ae7ec8 100644 --- a/reactos/dll/win32/rpcrt4/rpc_binding.h +++ b/reactos/dll/win32/rpcrt4/rpc_binding.h @@ -15,29 +15,92 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_RPC_BINDING_H #define __WINE_RPC_BINDING_H #include "wine/rpcss_shared.h" +#include "security.h" +#include "wine/list.h" + + +typedef struct _RpcAuthInfo +{ + LONG refs; + + ULONG AuthnLevel; + ULONG AuthnSvc; + CredHandle cred; + TimeStamp exp; + ULONG cbMaxToken; +} RpcAuthInfo; + +typedef struct _RpcQualityOfService +{ + LONG refs; + + RPC_SECURITY_QOS_V2_W *qos; +} RpcQualityOfService; + +typedef struct _RpcAssoc +{ + struct list entry; /* entry in the global list of associations */ + LONG refs; + + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + LPWSTR NetworkOptions; + RpcAuthInfo *AuthInfo; + + CRITICAL_SECTION cs; + struct list connection_pool; +} RpcAssoc; + +struct connection_ops; typedef struct _RpcConnection { struct _RpcConnection* Next; struct _RpcBinding* Used; BOOL server; - LPSTR Protseq; LPSTR NetworkAddr; LPSTR Endpoint; - HANDLE conn, thread; - OVERLAPPED ovl[2]; + LPWSTR NetworkOptions; + const struct connection_ops *ops; USHORT MaxTransmissionSize; /* The active interface bound to server. */ RPC_SYNTAX_IDENTIFIER ActiveInterface; + USHORT NextCallId; + + /* authentication */ + CtxtHandle ctx; + TimeStamp exp; + ULONG attr; + RpcAuthInfo *AuthInfo; + ULONG encryption_auth_len; + ULONG signature_auth_len; + RpcQualityOfService *QOS; + + /* client-only */ + struct list conn_pool_entry; } RpcConnection; +struct connection_ops { + const char *name; + unsigned char epm_protocols[2]; /* only floors 3 and 4. see http://www.opengroup.org/onlinepubs/9629399/apdxl.htm */ + RpcConnection *(*alloc)(void); + RPC_STATUS (*open_connection_client)(RpcConnection *conn); + RPC_STATUS (*handoff)(RpcConnection *old_conn, RpcConnection *new_conn); + int (*read)(RpcConnection *conn, void *buffer, unsigned int len); + int (*write)(RpcConnection *conn, const void *buffer, unsigned int len); + int (*close)(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); +}; + /* don't know what MS's structure looks like */ typedef struct _RpcBinding { @@ -48,32 +111,44 @@ typedef struct _RpcBinding LPSTR Protseq; LPSTR NetworkAddr; LPSTR Endpoint; + LPWSTR NetworkOptions; RPC_BLOCKING_FN BlockingFn; ULONG ServerTid; RpcConnection* FromConn; + RpcAssoc *Assoc; + + /* authentication */ + RpcAuthInfo *AuthInfo; + RpcQualityOfService *QOS; } RpcBinding; LPSTR RPCRT4_strndupA(LPCSTR src, INT len); -LPWSTR RPCRT4_strndupW(LPWSTR src, INT len); -LPSTR RPCRT4_strdupWtoA(LPWSTR src); -LPWSTR RPCRT4_strdupAtoW(LPSTR src); +LPWSTR RPCRT4_strndupW(LPCWSTR src, INT len); +LPSTR RPCRT4_strdupWtoA(LPCWSTR src); +LPWSTR RPCRT4_strdupAtoW(LPCSTR src); void RPCRT4_strfree(LPSTR src); #define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1) #define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1) -RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding); +ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo); +ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo); +ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos); +ULONG RpcQualityOfService_Release(RpcQualityOfService *qos); + +RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc); +RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo, const RpcQualityOfService *QOS); +void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection); +ULONG RpcAssoc_Release(RpcAssoc *assoc); + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, RpcBinding* Binding); RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); -RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection); RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection); RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection); -RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq); -RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq); -RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions); -RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions); -RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint); -RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid); +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPCSTR Endpoint); +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, const UUID* ObjectUuid); RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection); RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding); RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding); @@ -83,4 +158,35 @@ BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPC HANDLE RPCRT4_GetMasterMutex(void); HANDLE RPCRT4_RpcssNPConnect(void); +static inline const char *rpcrt4_conn_get_name(RpcConnection *Connection) +{ + return Connection->ops->name; +} + +static inline int rpcrt4_conn_read(RpcConnection *Connection, + void *buffer, unsigned int len) +{ + return Connection->ops->read(Connection, buffer, len); +} + +static inline int rpcrt4_conn_write(RpcConnection *Connection, + const void *buffer, unsigned int len) +{ + return Connection->ops->write(Connection, buffer, len); +} + +static inline int rpcrt4_conn_close(RpcConnection *Connection) +{ + return Connection->ops->close(Connection); +} + +static inline RPC_STATUS rpcrt4_conn_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + return old_conn->ops->handoff(old_conn, new_conn); +} + +/* floors 3 and up */ +RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, size_t *tower_size, const char *protseq, const char *networkaddr, const char *endpoint); +RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, size_t tower_size, char **protseq, char **networkaddr, char **endpoint); + #endif diff --git a/reactos/dll/win32/rpcrt4/rpc_defs.h b/reactos/dll/win32/rpcrt4/rpc_defs.h index 9e9a7359b10..7499dcd1c1d 100644 --- a/reactos/dll/win32/rpcrt4/rpc_defs.h +++ b/reactos/dll/win32/rpcrt4/rpc_defs.h @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_RPC_DEFS_H @@ -58,10 +58,10 @@ typedef struct RpcPktCommonHdr common; unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ unsigned short context_id; /* Presentation context identifier */ - unsigned char alert_count; /* Pending alert count */ - unsigned char padding[3]; /* Force alignment! */ + unsigned char cancel_count; /* Received cancel count */ + unsigned char reserved; /* Force alignment! */ unsigned long status; /* Runtime fault code (RPC_STATUS) */ - unsigned long reserved; + unsigned long reserved2; } RpcPktFaultHdr; typedef struct @@ -88,9 +88,8 @@ typedef struct typedef struct { - unsigned char padding1[2]; /* Force alignment! */ unsigned char num_results; /* Number of results */ - unsigned char padding2[3]; /* Force alignment! */ + unsigned char reserved[3]; /* Force alignment! */ struct { unsigned short result; unsigned short reason; @@ -106,6 +105,7 @@ typedef struct /* * Following this header are these fields: * RpcAddressString server_address; + * [0 - 3 bytes of padding so that results is 4-byte aligned] * RpcResults results; * RPC_SYNTAX_IDENTIFIER transfer; */ @@ -134,6 +134,18 @@ typedef union RpcPktBindNAckHdr bind_nack; } RpcPktHdr; +typedef struct +{ + unsigned char auth_type; /* authentication scheme in use */ + 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 */ +} RpcAuthVerifier; + +#define RPC_AUTH_VERIFIER_LEN(common_hdr) \ + ((common_hdr)->auth_len ? (common_hdr)->auth_len + sizeof(RpcAuthVerifier) : 0) + #define RPC_VER_MAJOR 5 #define RPC_VER_MINOR 0 @@ -160,6 +172,7 @@ typedef union #define PKT_BIND_NACK 13 #define PKT_ALTER_CONTEXT 14 #define PKT_ALTER_CONTEXT_RESP 15 +#define PKT_AUTH3 16 #define PKT_SHUTDOWN 17 #define PKT_CO_CANCEL 18 #define PKT_ORPHANED 19 diff --git a/reactos/dll/win32/rpcrt4/rpc_epmap.c b/reactos/dll/win32/rpcrt4/rpc_epmap.c index f7d01a1a190..45471c175b7 100644 --- a/reactos/dll/win32/rpcrt4/rpc_epmap.c +++ b/reactos/dll/win32/rpcrt4/rpc_epmap.c @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: * - actually do things right @@ -36,6 +36,7 @@ #include "wine/debug.h" #include "rpc_binding.h" +#include "epm_towers.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -67,7 +68,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * RpcEpRegisterA (RPCRT4.@) */ RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, - UUID_VECTOR *UuidVector, unsigned char *Annotation ) + UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) { RPCSS_NP_MESSAGE msg; RPCSS_NP_REPLY reply; @@ -245,3 +246,140 @@ RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE /* otherwise we fully bind the handle & return RPC_S_OK */ return RPCRT4_ResolveBinding(Binding, reply.as_string); } + +typedef unsigned int unsigned32; +typedef struct twr_t + { + unsigned32 tower_length; + /* [size_is] */ BYTE tower_octet_string[ 1 ]; + } twr_t; + +/*********************************************************************** + * TowerExplode (RPCRT4.@) + */ +RPC_STATUS WINAPI TowerExplode( + const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax, + char **protseq, char **endpoint, char **address) +{ + size_t tower_size; + RPC_STATUS status; + const unsigned char *p; + u_int16 floor_count; + const twr_uuid_floor_t *object_floor; + const twr_uuid_floor_t *syntax_floor; + + if (protseq) + *protseq = NULL; + if (endpoint) + *endpoint = NULL; + if (address) + *address = NULL; + + tower_size = tower->tower_length; + + if (tower_size < sizeof(u_int16)) + return EPT_S_NOT_REGISTERED; + + p = &tower->tower_octet_string[0]; + + floor_count = *(const u_int16 *)p; + p += sizeof(u_int16); + tower_size -= sizeof(u_int16); + TRACE("floor_count: %d\n", floor_count); + /* FIXME: should we do something with the floor count? at the moment we don't */ + + if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor)) + return EPT_S_NOT_REGISTERED; + + object_floor = (const twr_uuid_floor_t *)p; + p += sizeof(*object_floor); + tower_size -= sizeof(*object_floor); + syntax_floor = (const twr_uuid_floor_t *)p; + p += sizeof(*syntax_floor); + tower_size -= sizeof(*syntax_floor); + + if ((object_floor->count_lhs != sizeof(object_floor->protid) + + sizeof(object_floor->uuid) + sizeof(object_floor->major_version)) || + (object_floor->protid != EPM_PROTOCOL_UUID) || + (object_floor->count_rhs != sizeof(object_floor->minor_version))) + return EPT_S_NOT_REGISTERED; + + if ((syntax_floor->count_lhs != sizeof(syntax_floor->protid) + + sizeof(syntax_floor->uuid) + sizeof(syntax_floor->major_version)) || + (syntax_floor->protid != EPM_PROTOCOL_UUID) || + (syntax_floor->count_rhs != sizeof(syntax_floor->minor_version))) + return EPT_S_NOT_REGISTERED; + + status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint); + if ((status == RPC_S_OK) && syntax && object) + { + syntax->SyntaxGUID = syntax_floor->uuid; + syntax->SyntaxVersion.MajorVersion = syntax_floor->major_version; + syntax->SyntaxVersion.MinorVersion = syntax_floor->minor_version; + object->SyntaxGUID = object_floor->uuid; + object->SyntaxVersion.MajorVersion = object_floor->major_version; + object->SyntaxVersion.MinorVersion = object_floor->minor_version; + } + return status; +} + +/*********************************************************************** + * TowerConstruct (RPCRT4.@) + */ +RPC_STATUS WINAPI TowerConstruct( + const RPC_SYNTAX_IDENTIFIER *object, const RPC_SYNTAX_IDENTIFIER *syntax, + const char *protseq, const char *endpoint, const char *address, + twr_t **tower) +{ + size_t tower_size; + RPC_STATUS status; + unsigned char *p; + twr_uuid_floor_t *object_floor; + twr_uuid_floor_t *syntax_floor; + + *tower = NULL; + + status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint); + + if (status != RPC_S_OK) + return status; + + tower_size += sizeof(u_int16) + sizeof(*object_floor) + sizeof(*syntax_floor); + *tower = I_RpcAllocate(FIELD_OFFSET(twr_t, tower_octet_string[tower_size])); + if (!*tower) + return RPC_S_OUT_OF_RESOURCES; + + (*tower)->tower_length = tower_size; + p = &(*tower)->tower_octet_string[0]; + *(u_int16 *)p = 5; /* number of floors */ + p += sizeof(u_int16); + object_floor = (twr_uuid_floor_t *)p; + p += sizeof(*object_floor); + syntax_floor = (twr_uuid_floor_t *)p; + p += sizeof(*syntax_floor); + + object_floor->count_lhs = sizeof(object_floor->protid) + sizeof(object_floor->uuid) + + sizeof(object_floor->major_version); + object_floor->protid = EPM_PROTOCOL_UUID; + object_floor->count_rhs = sizeof(object_floor->minor_version); + object_floor->uuid = object->SyntaxGUID; + object_floor->major_version = object->SyntaxVersion.MajorVersion; + object_floor->minor_version = object->SyntaxVersion.MinorVersion; + + syntax_floor->count_lhs = sizeof(syntax_floor->protid) + sizeof(syntax_floor->uuid) + + sizeof(syntax_floor->major_version); + syntax_floor->protid = EPM_PROTOCOL_UUID; + syntax_floor->count_rhs = sizeof(syntax_floor->minor_version); + syntax_floor->uuid = syntax->SyntaxGUID; + syntax_floor->major_version = syntax->SyntaxVersion.MajorVersion; + syntax_floor->minor_version = syntax->SyntaxVersion.MinorVersion; + + status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint); + if (status != RPC_S_OK) + { + I_RpcFree(*tower); + *tower = NULL; + return status; + } + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4/rpc_message.c b/reactos/dll/win32/rpcrt4/rpc_message.c index 7c34719f55a..cf164cfadc7 100644 --- a/reactos/dll/win32/rpcrt4/rpc_message.c +++ b/reactos/dll/win32/rpcrt4/rpc_message.c @@ -3,6 +3,7 @@ * * Copyright 2001-2002 Ove Kåven, TransGaming Technologies * Copyright 2004 Filip Navara + * Copyright 2006 CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,11 +17,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -45,7 +42,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc); -static DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) +/* note: the DCE/RPC spec says the alignment amount should be 4, but + * MS/RPC servers seem to always use 16 */ +#define AUTH_ALIGNMENT 16 + +/* gets the amount needed to round a value up to the specified alignment */ +#define ROUND_UP_AMOUNT(value, alignment) \ + (((alignment) - (((value) % (alignment)))) % (alignment)) +#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) + +enum secure_packet_direction +{ + SECURE_PACKET_SEND, + SECURE_PACKET_RECEIVE +}; + +static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg); + +static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) { static const DWORD header_sizes[] = { sizeof(Header->request), 0, sizeof(Header->response), @@ -68,6 +82,19 @@ static DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) return ret; } +static int packet_has_body(const RpcPktHdr *Header) +{ + return (Header->common.ptype == PKT_FAULT) || + (Header->common.ptype == PKT_REQUEST) || + (Header->common.ptype == PKT_RESPONSE); +} + +static int packet_has_auth_verifier(const RpcPktHdr *Header) +{ + return !(Header->common.ptype == PKT_BIND_NACK) && + !(Header->common.ptype == PKT_SHUTDOWN); +} + static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, unsigned long DataRepresentation) { @@ -173,6 +200,22 @@ RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, return header; } +static RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->common) + 12); + if (header == NULL) + return NULL; + + RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation); + header->common.frag_len = 0x14; + header->common.auth_len = 0; + + return header; +} + RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor) @@ -207,9 +250,10 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, RpcResults *results; RPC_SYNTAX_IDENTIFIER *transfer_id; - header_size = sizeof(header->bind_ack) + sizeof(RpcResults) + - sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(RpcAddressString) + - strlen(ServerAddress); + header_size = sizeof(header->bind_ack) + + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) + + sizeof(RpcResults) + + sizeof(RPC_SYNTAX_IDENTIFIER); header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size); if (header == NULL) { @@ -223,7 +267,8 @@ RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, server_address = (RpcAddressString*)(&header->bind_ack + 1); server_address->length = strlen(ServerAddress) + 1; strcpy(server_address->string, ServerAddress); - results = (RpcResults*)((ULONG_PTR)server_address + sizeof(RpcAddressString) + server_address->length - 1); + /* results is 4-byte aligned */ + results = (RpcResults*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); results->num_results = 1; results->results[0].result = Result; results->results[0].reason = Reason; @@ -238,6 +283,310 @@ VOID RPCRT4_FreeHeader(RpcPktHdr *Header) HeapFree(GetProcessHeap(), 0, Header); } +static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, + enum secure_packet_direction dir, + RpcPktHdr *hdr, unsigned int hdr_size, + unsigned char *stub_data, unsigned int stub_data_size, + RpcAuthVerifier *auth_hdr, + unsigned char *auth_value, unsigned int auth_value_size) +{ + SecBufferDesc message; + SecBuffer buffers[4]; + SECURITY_STATUS sec_status; + + message.ulVersion = SECBUFFER_VERSION; + message.cBuffers = sizeof(buffers)/sizeof(buffers[0]); + message.pBuffers = buffers; + + buffers[0].cbBuffer = hdr_size; + buffers[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + buffers[0].pvBuffer = hdr; + buffers[1].cbBuffer = stub_data_size; + buffers[1].BufferType = SECBUFFER_DATA; + buffers[1].pvBuffer = stub_data; + buffers[2].cbBuffer = sizeof(*auth_hdr); + buffers[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + buffers[2].pvBuffer = auth_hdr; + buffers[3].cbBuffer = auth_value_size; + buffers[3].BufferType = SECBUFFER_TOKEN; + buffers[3].pvBuffer = auth_value; + + if (dir == SECURE_PACKET_SEND) + { + if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr)) + { + sec_status = EncryptMessage(&Connection->ctx, 0, &message, 0 /* FIXME */); + if (sec_status != SEC_E_OK) + { + ERR("EncryptMessage failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE) + { +#ifdef FIX_LATER + sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */); + if (sec_status != SEC_E_OK) + { + ERR("MakeSignature failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } +#else + return RPC_S_SEC_PKG_ERROR; +#endif + } + } + else if (dir == SECURE_PACKET_RECEIVE) + { + if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr)) + { + sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0); + if (sec_status != SEC_E_OK) + { + ERR("EncryptMessage failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE) + { +#ifdef FIX_LATER + sec_status = VerifySignature(&Connection->ctx, &message, 0 /* FIXME */, NULL); + if (sec_status != SEC_E_OK) + { + ERR("VerifySignature failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } +#else + return RPC_S_SEC_PKG_ERROR; +#endif + } + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RPCRT4_SendAuth (internal) + * + * Transmit a packet with authorization data over connection in acceptable fragments. + */ +static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header, + void *Buffer, unsigned int BufferLength, + void *Auth, unsigned int AuthLength) +{ + PUCHAR buffer_pos; + DWORD hdr_size; + LONG count; + unsigned char *pkt; + LONG alen; + RPC_STATUS status; + + buffer_pos = Buffer; + /* The packet building functions save the packet header size, so we can use it. */ + hdr_size = Header->common.frag_len; + if (AuthLength) + Header->common.auth_len = AuthLength; + else if (Connection->AuthInfo && packet_has_auth_verifier(Header)) + { + if ((Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(Header)) + Header->common.auth_len = Connection->encryption_auth_len; + else + Header->common.auth_len = Connection->signature_auth_len; + } + else + Header->common.auth_len = 0; + Header->common.flags |= RPC_FLG_FIRST; + Header->common.flags &= ~RPC_FLG_LAST; + + alen = RPC_AUTH_VERIFIER_LEN(&Header->common); + + while (!(Header->common.flags & RPC_FLG_LAST)) { + unsigned char auth_pad_len = Header->common.auth_len ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0; + unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len; + + /* decide if we need to split the packet into fragments */ + if (pkt_size <= Connection->MaxTransmissionSize) { + Header->common.flags |= RPC_FLG_LAST; + Header->common.frag_len = pkt_size; + } else { + auth_pad_len = 0; + /* make sure packet payload will be a multiple of 16 */ + Header->common.frag_len = + ((Connection->MaxTransmissionSize - hdr_size - alen) & ~(AUTH_ALIGNMENT-1)) + + hdr_size + alen; + } + + pkt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Header->common.frag_len); + + memcpy(pkt, Header, hdr_size); + + /* fragment consisted of header only and is the last one */ + if (hdr_size == Header->common.frag_len) + goto write; + + memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen); + + /* add the authorization info */ + if (Connection->AuthInfo && packet_has_auth_verifier(Header)) + { + RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen]; + + auth_hdr->auth_type = Connection->AuthInfo->AuthnSvc; + auth_hdr->auth_level = Connection->AuthInfo->AuthnLevel; + auth_hdr->auth_pad_length = auth_pad_len; + auth_hdr->auth_reserved = 0; + /* a unique number... */ + auth_hdr->auth_context_id = (unsigned long)Connection; + + if (AuthLength) + memcpy(auth_hdr + 1, Auth, AuthLength); + else + { + status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_SEND, + (RpcPktHdr *)pkt, hdr_size, + pkt + hdr_size, Header->common.frag_len - hdr_size - alen, + auth_hdr, + (unsigned char *)(auth_hdr + 1), Header->common.auth_len); + if (status != RPC_S_OK) + { + HeapFree(GetProcessHeap(), 0, pkt); + return status; + } + } + } + +write: + count = rpcrt4_conn_write(Connection, pkt, Header->common.frag_len); + HeapFree(GetProcessHeap(), 0, pkt); + if (count<0) { + WARN("rpcrt4_conn_write failed (auth)\n"); + return RPC_S_PROTOCOL_ERROR; + } + + buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len; + BufferLength -= Header->common.frag_len - hdr_size - alen - auth_pad_len; + Header->common.flags &= ~RPC_FLG_FIRST; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RPCRT4_ClientAuthorize (internal) + * + * Authorize a client connection. A NULL in param signifies a new connection. + */ +static RPC_STATUS RPCRT4_ClientAuthorize(RpcConnection *conn, SecBuffer *in, + SecBuffer *out) +{ + SECURITY_STATUS r; + SecBufferDesc out_desc; + SecBufferDesc inp_desc; + SecPkgContext_Sizes secctx_sizes; + BOOL continue_needed; + ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | + ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE; + + if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) + context_req |= ISC_REQ_INTEGRITY; + else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY; + + out->BufferType = SECBUFFER_TOKEN; + out->cbBuffer = conn->AuthInfo->cbMaxToken; + out->pvBuffer = HeapAlloc(GetProcessHeap(), 0, out->cbBuffer); + if (!out->pvBuffer) return ERROR_OUTOFMEMORY; + + out_desc.ulVersion = 0; + out_desc.cBuffers = 1; + out_desc.pBuffers = out; + + inp_desc.cBuffers = 1; + inp_desc.pBuffers = in; + inp_desc.ulVersion = 0; + + r = InitializeSecurityContextA(&conn->AuthInfo->cred, in ? &conn->ctx : NULL, + NULL, context_req, 0, SECURITY_NETWORK_DREP, + in ? &inp_desc : NULL, 0, &conn->ctx, &out_desc, &conn->attr, + &conn->exp); + if (FAILED(r)) + { + WARN("InitializeSecurityContext failed with error 0x%08x\n", r); + goto failed; + } + + TRACE("r = 0x%08x, attr = 0x%08x\n", r, conn->attr); + continue_needed = ((r == SEC_I_CONTINUE_NEEDED) || + (r == SEC_I_COMPLETE_AND_CONTINUE)); + + if ((r == SEC_I_COMPLETE_NEEDED) || (r == SEC_I_COMPLETE_AND_CONTINUE)) + { + TRACE("complete needed\n"); + r = CompleteAuthToken(&conn->ctx, &out_desc); + if (FAILED(r)) + { + WARN("CompleteAuthToken failed with error 0x%08x\n", r); + goto failed; + } + } + + TRACE("cbBuffer = %ld\n", out->cbBuffer); + + if (!continue_needed) + { +#ifdef FIX_LATER + r = QueryContextAttributesA(&conn->ctx, SECPKG_ATTR_SIZES, &secctx_sizes); + if (FAILED(r)) + { + WARN("QueryContextAttributes failed with error 0x%08x\n", r); + goto failed; + } + conn->signature_auth_len = secctx_sizes.cbMaxSignature; + conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer; +#else + goto failed; +#endif + } + + return RPC_S_OK; + +failed: + HeapFree(GetProcessHeap(), 0, out->pvBuffer); + out->pvBuffer = NULL; + return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */ +} + +/*********************************************************************** + * RPCRT4_AuthorizeBinding (internal) + */ +static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn, + BYTE *challenge, ULONG count) +{ + SecBuffer inp, out; + RpcPktHdr *resp_hdr; + RPC_STATUS status; + + TRACE("challenge %s, %d bytes\n", challenge, count); + + inp.BufferType = SECBUFFER_TOKEN; + inp.pvBuffer = challenge; + inp.cbBuffer = count; + + status = RPCRT4_ClientAuthorize(conn, &inp, &out); + if (status) return status; + + resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION); + if (!resp_hdr) + return E_OUTOFMEMORY; + + status = RPCRT4_SendAuth(conn, resp_hdr, NULL, 0, out.pvBuffer, out.cbBuffer); + + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + RPCRT4_FreeHeader(resp_hdr); + + return status; +} + /*********************************************************************** * RPCRT4_Send (internal) * @@ -246,57 +595,20 @@ VOID RPCRT4_FreeHeader(RpcPktHdr *Header) RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength) { - PUCHAR buffer_pos; - DWORD hdr_size, count; + RPC_STATUS r; + SecBuffer out; - buffer_pos = Buffer; - /* The packet building functions save the packet header size, so we can use it. */ - hdr_size = Header->common.frag_len; - Header->common.flags |= RPC_FLG_FIRST; - Header->common.flags &= ~RPC_FLG_LAST; - while (!(Header->common.flags & RPC_FLG_LAST)) { - /* decide if we need to split the packet into fragments */ - if ((BufferLength + hdr_size) <= Connection->MaxTransmissionSize) { - Header->common.flags |= RPC_FLG_LAST; - Header->common.frag_len = BufferLength + hdr_size; - } else { - Header->common.frag_len = Connection->MaxTransmissionSize; - } - - /* transmit packet header */ - if (!WriteFile(Connection->conn, Header, hdr_size, &count, &Connection->ovl[1]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("WriteFile failed with error %ld\n", GetLastError()); - return GetLastError(); - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - return GetLastError(); - } - - /* fragment consisted of header only and is the last one */ - if (hdr_size == Header->common.frag_len && - Header->common.flags & RPC_FLG_LAST) { - return RPC_S_OK; - } - - /* send the fragment data */ - if (!WriteFile(Connection->conn, buffer_pos, Header->common.frag_len - hdr_size, &count, &Connection->ovl[1]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("WriteFile failed with error %ld\n", GetLastError()); - return GetLastError(); - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - return GetLastError(); - } - - buffer_pos += Header->common.frag_len - hdr_size; - BufferLength -= Header->common.frag_len - hdr_size; - Header->common.flags &= ~RPC_FLG_FIRST; + if (!Connection->AuthInfo || SecIsValidHandle(&Connection->ctx)) + { + return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0); } - return RPC_S_OK; + /* tack on a negotiate packet */ + RPCRT4_ClientAuthorize(Connection, NULL, &out); + r = RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer); + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + + return r; } /*********************************************************************** @@ -308,11 +620,13 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg) { RPC_STATUS status; - DWORD dwRead, hdr_length; + DWORD hdr_length; + LONG dwRead; unsigned short first_flag; unsigned long data_length; unsigned long buffer_length; - unsigned char *buffer_ptr; + unsigned long auth_length; + unsigned char *auth_data = NULL; RpcPktCommonHdr common_hdr; *Header = NULL; @@ -320,21 +634,9 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, TRACE("(%p, %p, %p)\n", Connection, Header, pMsg); /* read packet common header */ - if (!ReadFile(Connection->conn, &common_hdr, sizeof(common_hdr), &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } + dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr)); if (dwRead != sizeof(common_hdr)) { - WARN("Short read of header, %ld/%d bytes\n", dwRead, sizeof(common_hdr)); + WARN("Short read of header, %d bytes\n", dwRead); status = RPC_S_PROTOCOL_ERROR; goto fail; } @@ -358,27 +660,13 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, memcpy(*Header, &common_hdr, sizeof(common_hdr)); /* read the rest of packet header */ - if (!ReadFile(Connection->conn, &(*Header)->common + 1, - hdr_length - sizeof(common_hdr), &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } + dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr)); if (dwRead != hdr_length - sizeof(common_hdr)) { - WARN("bad header length, %ld/%ld bytes\n", 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; } - /* read packet body */ switch (common_hdr.ptype) { case PKT_RESPONSE: @@ -388,7 +676,7 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, pMsg->BufferLength = (*Header)->request.alloc_hint; break; default: - pMsg->BufferLength = common_hdr.frag_len - hdr_length; + pMsg->BufferLength = common_hdr.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&common_hdr); } TRACE("buffer length = %u\n", pMsg->BufferLength); @@ -397,89 +685,157 @@ RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, if (status != RPC_S_OK) goto fail; first_flag = RPC_FLG_FIRST; + auth_length = common_hdr.auth_len; + if (auth_length) { + auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&common_hdr)); + if (!auth_data) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } buffer_length = 0; - buffer_ptr = pMsg->Buffer; - while (buffer_length < pMsg->BufferLength) + while (TRUE) { - data_length = (*Header)->common.frag_len - hdr_length; - if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag || - data_length + buffer_length > pMsg->BufferLength) { - TRACE("invalid packet flags or buffer length\n"); + unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&(*Header)->common); + + /* verify header fields */ + + if (((*Header)->common.frag_len < hdr_length) || + ((*Header)->common.frag_len - hdr_length < header_auth_len)) { + WARN("frag_len %d too small for hdr_length %d and auth_len %d\n", + (*Header)->common.frag_len, hdr_length, header_auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; } - if (data_length == 0) dwRead = 0; else { - if (!ReadFile(Connection->conn, buffer_ptr, data_length, &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); + if ((*Header)->common.auth_len != auth_length) { + WARN("auth_len header field changed from %ld to %d\n", + auth_length, (*Header)->common.auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag) { + TRACE("invalid packet flags\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + data_length = (*Header)->common.frag_len - hdr_length - header_auth_len; + if (data_length + buffer_length > pMsg->BufferLength) { + TRACE("allocation hint exceeded, new buffer length = %ld\n", + data_length + buffer_length); + pMsg->BufferLength = data_length + buffer_length; + status = I_RpcReAllocateBuffer(pMsg); + if (status != RPC_S_OK) goto fail; + } + + if (data_length == 0) dwRead = 0; else + dwRead = rpcrt4_conn_read(Connection, + (unsigned char *)pMsg->Buffer + buffer_length, data_length); + if (dwRead != data_length) { + WARN("bad data length, %d/%ld\n", dwRead, data_length); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (header_auth_len) { + if (header_auth_len < sizeof(RpcAuthVerifier)) { + WARN("bad auth verifier length %d\n", header_auth_len); status = RPC_S_PROTOCOL_ERROR; goto fail; } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } - } - if (dwRead != data_length) { - WARN("bad data length, %ld/%ld\n", dwRead, data_length); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - /* when there is no more data left, it should be the last packet */ - if (buffer_length == pMsg->BufferLength && - ((*Header)->common.flags & RPC_FLG_LAST) == 0) { - WARN("no more data left, but not last packet\n"); - status = RPC_S_PROTOCOL_ERROR; - goto fail; + /* FIXME: we should accumulate authentication data for the bind, + * bind_ack, alter_context and alter_context_response if necessary. + * however, the details of how this is done is very sketchy in the + * DCE/RPC spec. for all other packet types that have authentication + * verifier data then it is just duplicated in all the fragments */ + dwRead = rpcrt4_conn_read(Connection, auth_data, header_auth_len); + if (dwRead != header_auth_len) { + WARN("bad authentication data length, %d/%d\n", dwRead, + header_auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* these packets are handled specially, not by the generic SecurePacket + * function */ + if ((common_hdr.ptype != PKT_BIND) && + (common_hdr.ptype != PKT_BIND_ACK) && + (common_hdr.ptype != PKT_AUTH3)) + status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE, + *Header, hdr_length, + (unsigned char *)pMsg->Buffer + buffer_length, data_length, + (RpcAuthVerifier *)auth_data, + (unsigned char *)auth_data + sizeof(RpcAuthVerifier), + header_auth_len - sizeof(RpcAuthVerifier)); } buffer_length += data_length; - if (buffer_length < pMsg->BufferLength) { + if (!((*Header)->common.flags & RPC_FLG_LAST)) { TRACE("next header\n"); /* read the header of next packet */ - if (!ReadFile(Connection->conn, *Header, hdr_length, &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = GetLastError(); - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } + dwRead = rpcrt4_conn_read(Connection, *Header, hdr_length); if (dwRead != hdr_length) { - WARN("invalid packet header size (%ld)\n", dwRead); + WARN("invalid packet header size (%d)\n", dwRead); status = RPC_S_PROTOCOL_ERROR; goto fail; } - buffer_ptr += data_length; first_flag = 0; + } else { + break; } } + pMsg->BufferLength = buffer_length; + + /* respond to authorization request */ + if (common_hdr.ptype == PKT_BIND_ACK && auth_length > sizeof(RpcAuthVerifier)) + { + status = RPCRT_AuthorizeConnection(Connection, + auth_data + sizeof(RpcAuthVerifier), + auth_length); + if (status) + goto fail; + } /* success */ status = RPC_S_OK; fail: - if (status != RPC_S_OK && *Header) { + if (status != RPC_S_OK) { RPCRT4_FreeHeader(*Header); *Header = NULL; } + HeapFree(GetProcessHeap(), 0, auth_data); return status; } /*********************************************************************** * I_RpcGetBuffer [RPCRT4.@] + * + * Allocates a buffer for use by I_RpcSend or I_RpcSendReceive and binds to the + * server interface. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * Success: RPC_S_OK. + * Failure: RPC_S_INVALID_BINDING if pMsg->Handle is invalid. + * RPC_S_SERVER_UNAVAILABLE if unable to connect to server. + * ERROR_OUTOFMEMORY if buffer allocation failed. + * + * NOTES + * The pMsg->BufferLength field determines the size of the buffer to allocate, + * in bytes. + * + * Use I_RpcFreeBuffer() to unbind from the server and free the message buffer. + * + * SEE ALSO + * I_RpcFreeBuffer(), I_RpcSend(), I_RpcReceive(), I_RpcSendReceive(). */ RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) { @@ -492,8 +848,32 @@ RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) return pMsg->Buffer ? S_OK : E_OUTOFMEMORY; } +/*********************************************************************** + * I_RpcReAllocateBuffer (internal) + */ +static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg) +{ + TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); + pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength); + + TRACE("Buffer=%p\n", pMsg->Buffer); + return pMsg->Buffer ? RPC_S_OK : RPC_S_OUT_OF_RESOURCES; +} + /*********************************************************************** * I_RpcFreeBuffer [RPCRT4.@] + * + * Frees a buffer allocated by I_RpcGetBuffer or I_RpcReceive and unbinds from + * the server interface. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * RPC_S_OK. + * + * SEE ALSO + * I_RpcGetBuffer(), I_RpcReceive(). */ RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) { @@ -506,6 +886,20 @@ RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) /*********************************************************************** * I_RpcSend [RPCRT4.@] + * + * Sends a message to the server. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * Unknown. + * + * NOTES + * The buffer must have been allocated with I_RpcGetBuffer(). + * + * SEE ALSO + * I_RpcGetBuffer(), I_RpcReceive(), I_RpcSendReceive(). */ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) { @@ -527,6 +921,14 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) } else { cif = pMsg->RpcInterfaceInformation; if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + + if (!bind->Endpoint || !bind->Endpoint[0]) + { + TRACE("automatically resolving partially bound binding\n"); + status = RpcEpResolveBinding(bind, cif); + if (status != RPC_S_OK) return status; + } + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, &cif->InterfaceId); } @@ -545,6 +947,7 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation, pMsg->BufferLength, pMsg->ProcNum, &bind->ObjectUuid); + hdr->common.call_id = conn->NextCallId++; } status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength); @@ -555,10 +958,9 @@ RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) if (!bind->server) { /* save the connection, so the response can be read from it */ pMsg->ReservedForRuntime = conn; - return RPC_S_OK; + return status; } RPCRT4_CloseBinding(bind, conn); - status = RPC_S_OK; return status; } @@ -590,6 +992,14 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) } else { cif = pMsg->RpcInterfaceInformation; if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + + if (!bind->Endpoint || !bind->Endpoint[0]) + { + TRACE("automatically resolving partially bound binding\n"); + status = RpcEpResolveBinding(bind, cif); + if (status != RPC_S_OK) return status; + } + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, &cif->InterfaceId); } @@ -613,8 +1023,8 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) break; case PKT_FAULT: pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; - ERR ("we got fault packet with status %lx\n", hdr->fault.status); - status = RPC_S_CALL_FAILED; /* ? */ + ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status); + status = hdr->fault.status; /* FIXME: do translation from nca error codes */ goto fail; default: WARN("bad packet type %d\n", hdr->common.ptype); @@ -625,23 +1035,42 @@ RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) status = RPC_S_OK; fail: - if (hdr) { - RPCRT4_FreeHeader(hdr); - } + RPCRT4_FreeHeader(hdr); RPCRT4_CloseBinding(bind, conn); return status; } /*********************************************************************** * I_RpcSendReceive [RPCRT4.@] + * + * Sends a message to the server and receives the response. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * Success: RPC_S_OK. + * Failure: Any error code. + * + * NOTES + * The buffer must have been allocated with I_RpcGetBuffer(). + * + * SEE ALSO + * I_RpcGetBuffer(), I_RpcSend(), I_RpcReceive(). */ RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg) { RPC_STATUS status; + RPC_MESSAGE original_message; TRACE("(%p)\n", pMsg); + + original_message = *pMsg; status = I_RpcSend(pMsg); if (status == RPC_S_OK) status = I_RpcReceive(pMsg); + /* free the buffer replaced by a new buffer in I_RpcReceive */ + if (status == RPC_S_OK) + I_RpcFreeBuffer(&original_message); return status; } diff --git a/reactos/dll/win32/rpcrt4/rpc_message.h b/reactos/dll/win32/rpcrt4/rpc_message.h index 59ee9c050ec..97defb38871 100644 --- a/reactos/dll/win32/rpcrt4/rpc_message.h +++ b/reactos/dll/win32/rpcrt4/rpc_message.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_RPC_MESSAGE_H diff --git a/reactos/dll/win32/rpcrt4/rpc_misc.h b/reactos/dll/win32/rpcrt4/rpc_misc.h index 49c483e5c4b..0cb41c1b7be 100644 --- a/reactos/dll/win32/rpcrt4/rpc_misc.h +++ b/reactos/dll/win32/rpcrt4/rpc_misc.h @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */ diff --git a/reactos/dll/win32/rpcrt4/rpc_server.c b/reactos/dll/win32/rpcrt4/rpc_server.c index df83b65d548..71524531d40 100644 --- a/reactos/dll/win32/rpcrt4/rpc_server.c +++ b/reactos/dll/win32/rpcrt4/rpc_server.c @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * TODO: * - a whole lot @@ -47,13 +47,10 @@ #include "rpc_message.h" #include "rpc_defs.h" -#define MAX_THREADS 128 - WINE_DEFAULT_DEBUG_CHANNEL(rpc); typedef struct _RpcPacket { - struct _RpcPacket* next; struct _RpcConnection* conn; RpcPktHdr* hdr; RPC_MESSAGE* msg; @@ -69,8 +66,9 @@ typedef struct _RpcObjTypeMap static RpcObjTypeMap *RpcObjTypeMaps; -static RpcServerProtseq* protseqs; -static RpcServerInterface* ifs; +/* list of type RpcServerProtseq */ +static struct list protseqs = LIST_INIT(protseqs); +static struct list server_interfaces = LIST_INIT(server_interfaces); static CRITICAL_SECTION server_cs; static CRITICAL_SECTION_DEBUG server_cs_debug = @@ -96,31 +94,10 @@ static BOOL std_listen; static LONG manual_listen_count; /* total listeners including auto listeners */ static LONG listen_count; -/* set on change of configuration (e.g. listening on new protseq) */ -static HANDLE mgr_event; -/* mutex for ensuring only one thread can change state at a time */ -static HANDLE mgr_mutex; -/* set when server thread has finished opening connections */ -static HANDLE server_ready_event; - -static CRITICAL_SECTION spacket_cs; -static CRITICAL_SECTION_DEBUG spacket_cs_debug = -{ - 0, 0, &spacket_cs, - { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": spacket_cs") } -}; -static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 }; - -static RpcPacket* spacket_head; -static RpcPacket* spacket_tail; -static HANDLE server_sem; - -static LONG worker_count, worker_free, worker_tls; static UUID uuid_nil; -inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) +static inline RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) { RpcObjTypeMap *rslt = RpcObjTypeMaps; RPC_STATUS dummy; @@ -133,7 +110,7 @@ inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) return rslt; } -inline static UUID *LookupObjType(UUID *ObjUuid) +static inline UUID *LookupObjType(UUID *ObjUuid) { RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid); if (map) @@ -147,93 +124,54 @@ static RpcServerInterface* RPCRT4_find_interface(UUID* object, BOOL check_object) { UUID* MgrType = NULL; - RpcServerInterface* cif = NULL; + RpcServerInterface* cif; RPC_STATUS status; if (check_object) MgrType = LookupObjType(object); EnterCriticalSection(&server_cs); - cif = ifs; - while (cif) { + LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) { if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && - std_listen) break; - cif = cif->Next; + std_listen) { + InterlockedIncrement(&cif->CurrentCalls); + break; + } } LeaveCriticalSection(&server_cs); + if (&cif->entry == &server_interfaces) cif = NULL; TRACE("returning %p for %s\n", cif, debugstr_guid(object)); return cif; } -static void RPCRT4_push_packet(RpcPacket* packet) +static void RPCRT4_release_server_interface(RpcServerInterface *sif) { - packet->next = NULL; - EnterCriticalSection(&spacket_cs); - if (spacket_tail) { - spacket_tail->next = packet; - spacket_tail = packet; - } else { - spacket_head = packet; - spacket_tail = packet; + if (!InterlockedDecrement(&sif->CurrentCalls) && + sif->CallsCompletedEvent) { + /* sif must have been removed from server_interfaces before + * CallsCompletedEvent is set */ + SetEvent(sif->CallsCompletedEvent); + HeapFree(GetProcessHeap(), 0, sif); } - LeaveCriticalSection(&spacket_cs); } -static RpcPacket* RPCRT4_pop_packet(void) -{ - RpcPacket* packet; - EnterCriticalSection(&spacket_cs); - packet = spacket_head; - if (packet) { - spacket_head = packet->next; - if (!spacket_head) spacket_tail = NULL; - } - LeaveCriticalSection(&spacket_cs); - if (packet) packet->next = NULL; - return packet; -} - -#ifndef __REACTOS__ -typedef struct { - PRPC_MESSAGE msg; - void* buf; -} packet_state; - static WINE_EXCEPTION_FILTER(rpc_filter) { - packet_state* state; - PRPC_MESSAGE msg; - state = TlsGetValue(worker_tls); - msg = state->msg; - if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg); - msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; - msg->BufferLength = sizeof(DWORD); - I_RpcGetBuffer(msg); - *(DWORD*)msg->Buffer = GetExceptionCode(); - WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer); + WARN("exception caught with code 0x%08x = %d\n", GetExceptionCode(), GetExceptionCode()); TRACE("returning failure packet\n"); + /* catch every exception */ return EXCEPTION_EXECUTE_HANDLER; } -#endif static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg) { RpcServerInterface* sif; RPC_DISPATCH_FUNCTION func; -#ifndef __REACTOS__ - packet_state state; -#endif UUID *object_uuid; RpcPktHdr *response; void *buf = msg->Buffer; RPC_STATUS status; -#ifndef __REACTOS__ - state.msg = msg; - state.buf = buf; - TlsSetValue(worker_tls, &state); -#endif - switch (hdr->common.ptype) { case PKT_BIND: TRACE("got bind packet\n"); @@ -252,7 +190,8 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, RPC_VER_MAJOR, RPC_VER_MINOR); } else { - TRACE("accepting bind request on connection %p\n", conn); + TRACE("accepting bind request on connection %p for %s\n", conn, + debugstr_guid(&hdr->bind.abstract.SyntaxGUID)); /* accept. */ response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, @@ -265,9 +204,13 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA /* save the interface for later use */ conn->ActiveInterface = hdr->bind.abstract; conn->MaxTransmissionSize = hdr->bind.max_tsize; + + RPCRT4_release_server_interface(sif); } - if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK) + status = RPCRT4_Send(conn, response, NULL, 0); + RPCRT4_FreeHeader(response); + if (status != RPC_S_OK) goto fail; break; @@ -281,6 +224,7 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA status); RPCRT4_Send(conn, response, NULL, 0); + RPCRT4_FreeHeader(response); break; } @@ -291,6 +235,10 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA } sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE); + if (!sif) { + /* FIXME: send fault packet? */ + break; + } msg->RpcInterfaceInformation = sif->If; /* copy the endpoint vector from sif to msg so that midl-generated code will use it */ msg->ManagerEpv = sif->MgrEpv; @@ -319,25 +267,27 @@ static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSA MAKEWORD(hdr->common.drep[2], hdr->common.drep[3])); /* dispatch */ -#ifndef __REACTOS__ __TRY { if (func) func(msg); } __EXCEPT(rpc_filter) { - /* failure packet was created in rpc_filter */ + if (msg->Buffer != buf) I_RpcFreeBuffer(msg); + /* this will cause a failure packet to be sent in I_RpcSend */ + msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + msg->BufferLength = sizeof(DWORD); + I_RpcGetBuffer(msg); + *(DWORD*)msg->Buffer = GetExceptionCode(); } __ENDTRY -#else - if (func) func(msg); -#endif /* send response packet */ I_RpcSend(msg); msg->RpcInterfaceInformation = NULL; + RPCRT4_release_server_interface(sif); break; default: - FIXME("unhandled packet type\n"); + FIXME("unhandled packet type %u\n", hdr->common.ptype); break; } @@ -351,59 +301,17 @@ fail: I_RpcFreeBuffer(msg); msg->Buffer = NULL; RPCRT4_FreeHeader(hdr); -#ifndef __REACTOS__ - TlsSetValue(worker_tls, NULL); -#endif + HeapFree(GetProcessHeap(), 0, msg); } static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) { - DWORD obj; - RpcPacket* pkt; - - for (;;) { - /* idle timeout after 5s */ - obj = WaitForSingleObject(server_sem, 5000); - if (obj == WAIT_TIMEOUT) { - /* if another idle thread exist, self-destruct */ - if (worker_free > 1) break; - continue; - } - pkt = RPCRT4_pop_packet(); - if (!pkt) continue; - InterlockedDecrement(&worker_free); - for (;;) { - RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); - HeapFree(GetProcessHeap(), 0, pkt); - /* try to grab another packet here without waiting - * on the semaphore, in case it hits max */ - pkt = RPCRT4_pop_packet(); - if (!pkt) break; - /* decrement semaphore */ - WaitForSingleObject(server_sem, 0); - } - InterlockedIncrement(&worker_free); - } - InterlockedDecrement(&worker_free); - InterlockedDecrement(&worker_count); + RpcPacket *pkt = the_arg; + RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); + HeapFree(GetProcessHeap(), 0, pkt); return 0; } -static void RPCRT4_create_worker_if_needed(void) -{ - if (!worker_free && worker_count < MAX_THREADS) { - HANDLE thread; - InterlockedIncrement(&worker_count); - InterlockedIncrement(&worker_free); - thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL); - if (thread) CloseHandle(thread); - else { - InterlockedDecrement(&worker_free); - InterlockedDecrement(&worker_count); - } - } -} - static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) { RpcConnection* conn = (RpcConnection*)the_arg; @@ -426,6 +334,7 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) status = RPCRT4_Receive(conn, &hdr, msg); if (status != RPC_S_OK) { WARN("receive failed with error %lx\n", status); + HeapFree(GetProcessHeap(), 0, msg); break; } @@ -436,23 +345,20 @@ static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) packet->conn = conn; packet->hdr = hdr; packet->msg = msg; - RPCRT4_create_worker_if_needed(); - RPCRT4_push_packet(packet); - ReleaseSemaphore(server_sem, 1, NULL); + QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION); #endif msg = NULL; } - HeapFree(GetProcessHeap(), 0, msg); RPCRT4_DestroyConnection(conn); return 0; } -static void RPCRT4_new_client(RpcConnection* conn) +void RPCRT4_new_client(RpcConnection* conn) { HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL); if (!thread) { DWORD err = GetLastError(); - ERR("failed to create thread, error=%08lx\n", err); + ERR("failed to create thread, error=%08x\n", err); RPCRT4_DestroyConnection(conn); } /* we could set conn->thread, but then we'd have to make the io_thread wait @@ -465,128 +371,96 @@ static void RPCRT4_new_client(RpcConnection* conn) static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) { - HANDLE m_event = mgr_event, b_handle; - HANDLE *objs = NULL; - DWORD count, res; - RpcServerProtseq* cps; + int res; + unsigned int count; + void *objs = NULL; + RpcServerProtseq* cps = the_arg; RpcConnection* conn; - RpcConnection* cconn; BOOL set_ready_event = FALSE; TRACE("(the_arg == ^%p)\n", the_arg); for (;;) { - EnterCriticalSection(&server_cs); - /* open and count connections */ - count = 1; - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - RPCRT4_OpenConnection(conn); - if (conn->ovl[0].hEvent) count++; - conn = conn->Next; - } - cps = cps->Next; - } - /* make array of connections */ - if (objs) - objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE)); - else - objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE)); - - objs[0] = m_event; - count = 1; - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - if (conn->ovl[0].hEvent) objs[count++] = conn->ovl[0].hEvent; - conn = conn->Next; - } - cps = cps->Next; - } - LeaveCriticalSection(&server_cs); + objs = cps->ops->get_wait_array(cps, objs, &count); if (set_ready_event) { /* signal to function that changed state that we are now sync'ed */ - SetEvent(server_ready_event); + SetEvent(cps->server_ready_event); set_ready_event = FALSE; } /* start waiting */ - res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); - if (res == WAIT_OBJECT_0) { + res = cps->ops->wait_for_new_connection(cps, count, objs); + if (res == -1) + break; + else if (res == 0) + { if (!std_listen) { - SetEvent(server_ready_event); + SetEvent(cps->server_ready_event); break; } set_ready_event = TRUE; } - else if (res == WAIT_FAILED) { - ERR("wait failed\n"); - } - else { - b_handle = objs[res - WAIT_OBJECT_0]; - /* find which connection got a RPC */ - EnterCriticalSection(&server_cs); - conn = NULL; - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - if (conn->ovl[0].hEvent == b_handle) break; - conn = conn->Next; - } - if (conn) break; - cps = cps->Next; - } - cconn = NULL; - if (conn) RPCRT4_SpawnConnection(&cconn, conn); - LeaveCriticalSection(&server_cs); - if (!conn) { - ERR("failed to locate connection for handle %p\n", b_handle); - } - if (cconn) RPCRT4_new_client(cconn); - } } - HeapFree(GetProcessHeap(), 0, objs); - EnterCriticalSection(&server_cs); + cps->ops->free_wait_array(cps, objs); + EnterCriticalSection(&cps->cs); /* close connections */ - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - RPCRT4_CloseConnection(conn); - conn = conn->Next; - } - cps = cps->Next; + conn = cps->conn; + while (conn) { + RPCRT4_CloseConnection(conn); + conn = conn->Next; } - LeaveCriticalSection(&server_cs); + LeaveCriticalSection(&cps->cs); return 0; } /* tells the server thread that the state has changed and waits for it to * make the changes */ -static void RPCRT4_sync_with_server_thread(void) +static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps) { /* make sure we are the only thread sync'ing the server state, otherwise * there is a race with the server thread setting an older state and setting * the server_ready_event when the new state hasn't yet been applied */ - WaitForSingleObject(mgr_mutex, INFINITE); + WaitForSingleObject(ps->mgr_mutex, INFINITE); + + ps->ops->signal_state_changed(ps); - SetEvent(mgr_event); /* wait for server thread to make the requested changes before returning */ - WaitForSingleObject(server_ready_event, INFINITE); + WaitForSingleObject(ps->server_ready_event, INFINITE); - ReleaseMutex(mgr_mutex); + ReleaseMutex(ps->mgr_mutex); +} + +static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen) +{ + RPC_STATUS status = RPC_S_OK; + HANDLE server_thread; + + EnterCriticalSection(&listen_cs); + if (ps->is_listening) goto done; + + if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL); + if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL); + if (!server_thread) + { + status = RPC_S_OUT_OF_RESOURCES; + goto done; + } + ps->is_listening = TRUE; + CloseHandle(server_thread); + +done: + LeaveCriticalSection(&listen_cs); + return status; } static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen) { RPC_STATUS status = RPC_S_ALREADY_LISTENING; + RpcServerProtseq *cps; TRACE("\n"); @@ -594,21 +468,27 @@ static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen) if (auto_listen || (manual_listen_count++ == 0)) { status = RPC_S_OK; - if (++listen_count == 1) { - HANDLE server_thread; - /* first listener creates server thread */ - if (!mgr_mutex) mgr_mutex = CreateMutexW(NULL, FALSE, NULL); - if (!mgr_event) mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!server_ready_event) server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!server_sem) server_sem = CreateSemaphoreW(NULL, 0, MAX_THREADS, NULL); - if (!worker_tls) worker_tls = TlsAlloc(); + if (++listen_count == 1) std_listen = TRUE; - server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL); - CloseHandle(server_thread); - } } LeaveCriticalSection(&listen_cs); + if (std_listen) + { + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) + { + status = RPCRT4_start_listen_protseq(cps, TRUE); + if (status != RPC_S_OK) + break; + + /* make sure server is actually listening on the interface before + * returning */ + RPCRT4_sync_with_server_thread(cps); + } + LeaveCriticalSection(&server_cs); + } + return status; } @@ -618,9 +498,14 @@ static void RPCRT4_stop_listen(BOOL auto_listen) if (auto_listen || (--manual_listen_count == 0)) { if (listen_count != 0 && --listen_count == 0) { + RpcServerProtseq *cps; + std_listen = FALSE; LeaveCriticalSection(&listen_cs); - RPCRT4_sync_with_server_thread(); + + LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) + RPCRT4_sync_with_server_thread(cps); + return; } assert(listen_count >= 0); @@ -628,18 +513,22 @@ static void RPCRT4_stop_listen(BOOL auto_listen) LeaveCriticalSection(&listen_cs); } -static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps) +static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, LPSTR endpoint) { - RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL); + RPC_STATUS status; - EnterCriticalSection(&server_cs); - ps->Next = protseqs; - protseqs = ps; - LeaveCriticalSection(&server_cs); + status = ps->ops->open_endpoint(ps, endpoint); + if (status != RPC_S_OK) + return status; - if (std_listen) RPCRT4_sync_with_server_thread(); + if (std_listen) + { + status = RPCRT4_start_listen_protseq(ps, FALSE); + if (status == RPC_S_OK) + RPCRT4_sync_with_server_thread(ps); + } - return RPC_S_OK; + return status; } /*********************************************************************** @@ -660,14 +549,14 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) EnterCriticalSection(&server_cs); /* count connections */ count = 0; - ps = protseqs; - while (ps) { + LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) { + EnterCriticalSection(&ps->cs); conn = ps->conn; while (conn) { count++; conn = conn->Next; } - ps = ps->Next; + LeaveCriticalSection(&ps->cs); } if (count) { /* export bindings */ @@ -676,8 +565,8 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) sizeof(RPC_BINDING_HANDLE)*(count-1)); (*BindingVector)->Count = count; count = 0; - ps = protseqs; - while (ps) { + LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) { + EnterCriticalSection(&ps->cs); conn = ps->conn; while (conn) { RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count], @@ -685,7 +574,7 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) count++; conn = conn->Next; } - ps = ps->Next; + LeaveCriticalSection(&ps->cs); } status = RPC_S_OK; } else { @@ -699,7 +588,7 @@ RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) /*********************************************************************** * RpcServerUseProtseqEpA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor ) +RPC_STATUS WINAPI RpcServerUseProtseqEpA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor ) { RPC_POLICY policy; @@ -716,7 +605,7 @@ RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, /*********************************************************************** * RpcServerUseProtseqEpW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor ) +RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor ) { RPC_POLICY policy; @@ -730,50 +619,114 @@ RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); } +/*********************************************************************** + * alloc_serverprotoseq (internal) + * + * Must be called with server_cs held. + */ +static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, char *Protseq, RpcServerProtseq **ps) +{ + const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq); + + if (!ops) + { + FIXME("protseq %s not supported\n", debugstr_a(Protseq)); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + + *ps = ops->alloc(); + if (!*ps) + return RPC_S_OUT_OF_RESOURCES; + (*ps)->MaxCalls = MaxCalls; + (*ps)->Protseq = Protseq; + (*ps)->ops = ops; + (*ps)->MaxCalls = 0; + (*ps)->conn = NULL; + InitializeCriticalSection(&(*ps)->cs); + (*ps)->is_listening = FALSE; + (*ps)->mgr_mutex = NULL; + (*ps)->server_ready_event = NULL; + + list_add_head(&protseqs, &(*ps)->entry); + + TRACE("new protseq %p created for %s\n", *ps, Protseq); + + return RPC_S_OK; +} + +/* 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) +{ + RPC_STATUS status; + RpcServerProtseq *cps; + + EnterCriticalSection(&server_cs); + + LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) + if (!strcmp(cps->Protseq, Protseq)) + { + TRACE("found existing protseq object for %s\n", Protseq); + *ps = cps; + LeaveCriticalSection(&server_cs); + return S_OK; + } + + status = alloc_serverprotoseq(MaxCalls, Protseq, ps); + + LeaveCriticalSection(&server_cs); + + return status; +} + /*********************************************************************** * RpcServerUseProtseqEpExA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor, +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,%lu,%lu})\n", debugstr_a( (char*)Protseq ), MaxCalls, - debugstr_a( (char*)Endpoint ), SecurityDescriptor, + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a(szps), MaxCalls, + debugstr_a(szep), SecurityDescriptor, lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); - ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); - ps->MaxCalls = MaxCalls; - ps->Protseq = RPCRT4_strdupA((char*)Protseq); - ps->Endpoint = RPCRT4_strdupA((char*)Endpoint); + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, RPCRT4_strdupA(szps), &ps); + if (status != RPC_S_OK) + return status; - return RPCRT4_use_protseq(ps); + return RPCRT4_use_protseq(ps, szep); } /*********************************************************************** * RpcServerUseProtseqEpExW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor, +RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor, PRPC_POLICY lpPolicy ) { RpcServerProtseq* ps; + RPC_STATUS status; + LPSTR EndpointA; TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor, lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); - ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); - ps->MaxCalls = MaxCalls; - ps->Protseq = RPCRT4_strdupWtoA(Protseq); - ps->Endpoint = RPCRT4_strdupWtoA(Endpoint); + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, RPCRT4_strdupWtoA(Protseq), &ps); + if (status != RPC_S_OK) + return status; - return RPCRT4_use_protseq(ps); + EndpointA = RPCRT4_strdupWtoA(Endpoint); + status = RPCRT4_use_protseq(ps, EndpointA); + RPCRT4_strfree(EndpointA); + return status; } /*********************************************************************** * RpcServerUseProtseqA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) { TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor); return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor); @@ -782,7 +735,7 @@ RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxC /*********************************************************************** * RpcServerUseProtseqW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) { TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor); return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor); @@ -852,17 +805,11 @@ RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, sif->IfCallbackFn = IfCallbackFn; EnterCriticalSection(&server_cs); - sif->Next = ifs; - ifs = sif; + list_add_head(&server_interfaces, &sif->entry); LeaveCriticalSection(&server_cs); - if (sif->Flags & RPC_IF_AUTOLISTEN) { - RPCRT4_start_listen(TRUE); - - /* make sure server is actually listening on the interface before - * returning */ - RPCRT4_sync_with_server_thread(); - } + if (sif->Flags & RPC_IF_AUTOLISTEN) + RPCRT4_start_listen(TRUE); return RPC_S_OK; } @@ -872,8 +819,45 @@ RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, */ RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete ) { - FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n", - IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete); + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + HANDLE event = NULL; + BOOL found = FALSE; + BOOL completed = TRUE; + RpcServerInterface *cif; + RPC_STATUS status; + + TRACE("(IfSpec == (RPC_IF_HANDLE)^%p (%s), MgrTypeUuid == %s, WaitForCallsToComplete == %u)\n", + IfSpec, debugstr_guid(&If->InterfaceId.SyntaxGUID), debugstr_guid(MgrTypeUuid), WaitForCallsToComplete); + + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) { + if ((!IfSpec || !memcmp(&If->InterfaceId, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER))) && + UuidEqual(MgrTypeUuid, &cif->MgrTypeUuid, &status)) { + list_remove(&cif->entry); + if (cif->CurrentCalls) { + completed = FALSE; + if (WaitForCallsToComplete) + cif->CallsCompletedEvent = event = CreateEventW(NULL, FALSE, FALSE, NULL); + } + found = TRUE; + break; + } + } + LeaveCriticalSection(&server_cs); + + if (!found) { + ERR("not found for object %s\n", debugstr_guid(MgrTypeUuid)); + return RPC_S_UNKNOWN_IF; + } + + if (completed) + HeapFree(GetProcessHeap(), 0, cif); + else if (event) { + /* sif will be freed when the last call is completed, so be careful not to + * touch that memory here as that could happen before we get here */ + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } return RPC_S_OK; } @@ -956,10 +940,10 @@ RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid ) /*********************************************************************** * RpcServerRegisterAuthInfoA (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, +RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( RPC_CSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, LPVOID Arg ) { - FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg ); + FIXME( "(%s,%u,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg ); return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ } @@ -967,10 +951,10 @@ RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, un /*********************************************************************** * RpcServerRegisterAuthInfoW (RPCRT4.@) */ -RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, +RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( RPC_WSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, LPVOID Arg ) { - FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg ); + FIXME( "(%s,%u,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg ); return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ } @@ -980,18 +964,15 @@ RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned l */ RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait ) { - RPC_STATUS status; + RPC_STATUS status = RPC_S_OK; TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait); - if (!protseqs) + if (list_empty(&protseqs)) return RPC_S_NO_PROTSEQS_REGISTERED; status = RPCRT4_start_listen(FALSE); - if (status == RPC_S_OK) - RPCRT4_sync_with_server_thread(); - if (DontWait || (status != RPC_S_OK)) return status; return RpcMgmtWaitServerListen(); @@ -1013,6 +994,8 @@ RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) LeaveCriticalSection(&listen_cs); + FIXME("not waiting for server calls to finish\n"); + return RPC_S_OK; } @@ -1033,6 +1016,15 @@ RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding ) return RPC_S_OK; } +/*********************************************************************** + * RpcMgmtEnableIdleCleanup (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtEnableIdleCleanup(void) +{ + FIXME("(): stub\n"); + return RPC_S_OK; +} + /*********************************************************************** * I_RpcServerStartListening (RPCRT4.@) */ @@ -1058,7 +1050,45 @@ RPC_STATUS WINAPI I_RpcServerStopListening( void ) */ UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam ) { - FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam ); + FIXME( "(%p,%08x,%08x,%08x): stub\n", hWnd, Message, wParam, lParam ); return 0; } + +/*********************************************************************** + * RpcMgmtInqIfIds (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR **IfIdVector) +{ + FIXME("(%p,%p): stub\n", Binding, IfIdVector); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcMgmtEpEltInqBegin (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE Binding, ULONG InquiryType, + RPC_IF_ID *IfId, ULONG VersOption, UUID *ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext) +{ + FIXME("(%p,%u,%p,%u,%p,%p): stub\n", + Binding, InquiryType, IfId, VersOption, ObjectUuid, InquiryContext); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcMgmtIsServerListening (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding) +{ + FIXME("(%p): stub\n", Binding); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcMgmtSetServerStackSize (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize) +{ + FIXME("(0x%x): stub\n", ThreadStackSize); + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4/rpc_server.h b/reactos/dll/win32/rpcrt4/rpc_server.h index 1f43de8d024..eb32be6afc9 100644 --- a/reactos/dll/win32/rpcrt4/rpc_server.h +++ b/reactos/dll/win32/rpcrt4/rpc_server.h @@ -15,26 +15,53 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_RPC_SERVER_H #define __WINE_RPC_SERVER_H #include "rpc_binding.h" +#include "wine/list.h" + +struct protseq_ops; typedef struct _RpcServerProtseq { - struct _RpcServerProtseq* Next; - LPSTR Protseq; - LPSTR Endpoint; - UINT MaxCalls; - RpcConnection* conn; + const struct protseq_ops *ops; /* RO */ + struct list entry; /* CS ::server_cs */ + LPSTR Protseq; /* RO */ + UINT MaxCalls; /* RO */ + /* list of listening connections */ + RpcConnection* conn; /* CS cs */ + CRITICAL_SECTION cs; + + /* is the server currently listening? */ + BOOL is_listening; /* CS ::listen_cs */ + /* mutex for ensuring only one thread can change state at a time */ + HANDLE mgr_mutex; + /* set when server thread has finished opening connections */ + HANDLE server_ready_event; } RpcServerProtseq; +struct protseq_ops +{ + const char *name; + RpcServerProtseq *(*alloc)(void); + void (*signal_state_changed)(RpcServerProtseq *protseq); + /* previous array is passed in to allow reuse of memory */ + void *(*get_wait_array)(RpcServerProtseq *protseq, void *prev_array, unsigned int *count); + void (*free_wait_array)(RpcServerProtseq *protseq, void *array); + /* returns -1 for failure, 0 for server state changed and 1 to indicate a + * 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); +}; + typedef struct _RpcServerInterface { - struct _RpcServerInterface* Next; + struct list entry; RPC_SERVER_INTERFACE* If; UUID MgrTypeUuid; RPC_MGR_EPV* MgrEpv; @@ -42,6 +69,13 @@ typedef struct _RpcServerInterface UINT MaxCalls; UINT MaxRpcSize; RPC_IF_CALLBACK_FN* IfCallbackFn; + LONG CurrentCalls; /* number of calls currently executing */ + /* set when unregistering interface to let the caller of + * RpcServerUnregisterIf* know that all calls have finished */ + HANDLE CallsCompletedEvent; } RpcServerInterface; +void RPCRT4_new_client(RpcConnection* conn); +const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq); + #endif /* __WINE_RPC_SERVER_H */ diff --git a/reactos/dll/win32/rpcrt4/rpc_transport.c b/reactos/dll/win32/rpcrt4/rpc_transport.c new file mode 100644 index 00000000000..7b460526bed --- /dev/null +++ b/reactos/dll/win32/rpcrt4/rpc_transport.c @@ -0,0 +1,1689 @@ +/* + * RPC transport layer + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2003 Mike Hearn + * Copyright 2004 Filip Navara + * Copyright 2006 Mike McCormack + * Copyright 2006 Damjan Jovanovic + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETINET_TCP_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_SYS_POLL_H +#include +#endif + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winerror.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/unicode.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_message.h" +#include "rpc_server.h" +#include "epm_towers.h" + +#ifndef SOL_TCP +# define SOL_TCP IPPROTO_TCP +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +static CRITICAL_SECTION assoc_list_cs; +static CRITICAL_SECTION_DEBUG assoc_list_cs_debug = +{ + 0, 0, &assoc_list_cs, + { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") } +}; +static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list assoc_list = LIST_INIT(assoc_list); + +/**** ncacn_np support ****/ + +typedef struct _RpcConnection_np +{ + RpcConnection common; + HANDLE pipe; + OVERLAPPED ovl; + BOOL listening; +} RpcConnection_np; + +static RpcConnection *rpcrt4_conn_np_alloc(void) +{ + RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np)); + if (npc) + { + npc->pipe = NULL; + memset(&npc->ovl, 0, sizeof(npc->ovl)); + npc->listening = FALSE; + } + return &npc->common; +} + +static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc) +{ + if (npc->listening) + return RPC_S_OK; + + npc->listening = TRUE; + if (ConnectNamedPipe(npc->pipe, &npc->ovl)) + return RPC_S_OK; + + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SetEvent(npc->ovl.hEvent); + return RPC_S_OK; + } + if (GetLastError() == ERROR_IO_PENDING) { + /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */ + return RPC_S_OK; + } + npc->listening = FALSE; + WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError()); + return RPC_S_OUT_OF_RESOURCES; +} + +static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + TRACE("listening on %s\n", pname); + + npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + if (npc->pipe == INVALID_HANDLE_VALUE) { + WARN("CreateNamedPipe failed with error %d\n", GetLastError()); + if (GetLastError() == ERROR_FILE_EXISTS) + return RPC_S_DUPLICATE_ENDPOINT; + else + return RPC_S_CANT_CREATE_ENDPOINT; + } + + memset(&npc->ovl, 0, sizeof(npc->ovl)); + npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + /* Note: we don't call ConnectNamedPipe here because it must be done in the + * server thread as the thread must be alertable */ + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + HANDLE pipe; + DWORD err, dwMode; + + TRACE("connecting to %s\n", pname); + + while (TRUE) { + DWORD dwFlags = 0; + if (Connection->QOS) + { + dwFlags = SECURITY_SQOS_PRESENT; + switch (Connection->QOS->qos->ImpersonationType) + { + case RPC_C_IMP_LEVEL_DEFAULT: + /* FIXME: what to do here? */ + break; + case RPC_C_IMP_LEVEL_ANONYMOUS: + dwFlags |= SECURITY_ANONYMOUS; + break; + case RPC_C_IMP_LEVEL_IDENTIFY: + dwFlags |= SECURITY_IDENTIFICATION; + break; + case RPC_C_IMP_LEVEL_IMPERSONATE: + dwFlags |= SECURITY_IMPERSONATION; + break; + case RPC_C_IMP_LEVEL_DELEGATE: + dwFlags |= SECURITY_DELEGATION; + break; + } + if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC) + dwFlags |= SECURITY_CONTEXT_TRACKING; + } + pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, dwFlags, 0); + if (pipe != INVALID_HANDLE_VALUE) break; + err = GetLastError(); + if (err == ERROR_PIPE_BUSY) { + TRACE("connection failed, error=%x\n", err); + return RPC_S_SERVER_TOO_BUSY; + } + if (!wait) + return RPC_S_SERVER_UNAVAILABLE; + if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { + err = GetLastError(); + WARN("connection failed, error=%x\n", err); + return RPC_S_SERVER_UNAVAILABLE; + } + } + + /* success */ + memset(&npc->ovl, 0, sizeof(npc->ovl)); + /* pipe is connected; change to message-read mode. */ + dwMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL); + npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + npc->pipe = pipe; + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; + RPC_STATUS r; + LPSTR pname; + + /* already connected? */ + if (npc->pipe) + return RPC_S_OK; + + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_open_pipe(Connection, pname, TRUE); + I_RpcFree(pname); + + return r; +} + +static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint) +{ + static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; + RPC_STATUS r; + LPSTR pname; + RpcConnection *Connection; + + r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, + endpoint, NULL, NULL, NULL, NULL); + if (r != RPC_S_OK) + return r; + + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_create_pipe(Connection, pname); + I_RpcFree(pname); + + EnterCriticalSection(&protseq->cs); + Connection->Next = protseq->conn; + protseq->conn = Connection; + LeaveCriticalSection(&protseq->cs); + + return r; +} + +static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + static const char prefix[] = "\\\\."; + RPC_STATUS r; + LPSTR pname; + + /* already connected? */ + if (npc->pipe) + return RPC_S_OK; + + /* protseq=ncacn_np: named pipes */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_open_pipe(Connection, pname, FALSE); + I_RpcFree(pname); + + return r; +} + +static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint) +{ + static const char prefix[] = "\\\\."; + RPC_STATUS r; + LPSTR pname; + RpcConnection *Connection; + + r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, + endpoint, NULL, NULL, NULL, NULL); + if (r != RPC_S_OK) + return r; + + /* protseq=ncacn_np: named pipes */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_create_pipe(Connection, pname); + I_RpcFree(pname); + + EnterCriticalSection(&protseq->cs); + Connection->Next = protseq->conn; + protseq->conn = Connection; + LeaveCriticalSection(&protseq->cs); + + return r; +} + +static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc) +{ + /* because of the way named pipes work, we'll transfer the connected pipe + * to the child, then reopen the server binding to continue listening */ + + new_npc->pipe = old_npc->pipe; + new_npc->ovl = old_npc->ovl; + old_npc->pipe = 0; + memset(&old_npc->ovl, 0, sizeof(old_npc->ovl)); + old_npc->listening = FALSE; +} + +static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + RPC_STATUS status; + LPSTR pname; + static const char prefix[] = "\\\\."; + + rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); + + pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1); + strcat(strcpy(pname, prefix), old_conn->Endpoint); + status = rpcrt4_conn_create_pipe(old_conn, pname); + I_RpcFree(pname); + + return status; +} + +static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + RPC_STATUS status; + LPSTR pname; + static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; + + TRACE("%s\n", old_conn->Endpoint); + + rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); + + pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1); + strcat(strcpy(pname, prefix), old_conn->Endpoint); + status = rpcrt4_conn_create_pipe(old_conn, pname); + I_RpcFree(pname); + + return status; +} + +static int rpcrt4_conn_np_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + char *buf = buffer; + BOOL ret = TRUE; + unsigned int bytes_left = count; + + while (bytes_left) + { + DWORD bytes_read; + ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL); + if (!ret || !bytes_read) + break; + bytes_left -= bytes_read; + buf += bytes_read; + } + return ret ? count : -1; +} + +static int rpcrt4_conn_np_write(RpcConnection *Connection, + const void *buffer, unsigned int count) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + const char *buf = buffer; + BOOL ret = TRUE; + unsigned int bytes_left = count; + + while (bytes_left) + { + DWORD bytes_written; + ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL); + if (!ret || !bytes_written) + break; + bytes_left -= bytes_written; + buf += bytes_written; + } + return ret ? count : -1; +} + +static int rpcrt4_conn_np_close(RpcConnection *Connection) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + if (npc->pipe) { + FlushFileBuffers(npc->pipe); + CloseHandle(npc->pipe); + npc->pipe = 0; + } + if (npc->ovl.hEvent) { + CloseHandle(npc->ovl.hEvent); + npc->ovl.hEvent = 0; + } + return 0; +} + +static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + twr_empty_floor_t *smb_floor; + twr_empty_floor_t *nb_floor; + size_t size; + size_t networkaddr_size; + size_t endpoint_size; + + TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); + + networkaddr_size = strlen(networkaddr) + 1; + endpoint_size = strlen(endpoint) + 1; + size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size; + + if (!tower_data) + return size; + + smb_floor = (twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*smb_floor); + + smb_floor->count_lhs = sizeof(smb_floor->protid); + smb_floor->protid = EPM_PROTOCOL_SMB; + smb_floor->count_rhs = endpoint_size; + + memcpy(tower_data, endpoint, endpoint_size); + tower_data += endpoint_size; + + nb_floor = (twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*nb_floor); + + nb_floor->count_lhs = sizeof(nb_floor->protid); + nb_floor->protid = EPM_PROTOCOL_NETBIOS; + nb_floor->count_rhs = networkaddr_size; + + memcpy(tower_data, networkaddr, networkaddr_size); + tower_data += networkaddr_size; + + return size; +} + +static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data; + const twr_empty_floor_t *nb_floor; + + TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); + + if (tower_size < sizeof(*smb_floor)) + return EPT_S_NOT_REGISTERED; + + tower_data += sizeof(*smb_floor); + tower_size -= sizeof(*smb_floor); + + if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) || + (smb_floor->protid != EPM_PROTOCOL_SMB) || + (smb_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + + if (endpoint) + { + *endpoint = I_RpcAllocate(smb_floor->count_rhs); + if (!*endpoint) + return RPC_S_OUT_OF_RESOURCES; + memcpy(*endpoint, tower_data, smb_floor->count_rhs); + } + tower_data += smb_floor->count_rhs; + tower_size -= smb_floor->count_rhs; + + if (tower_size < sizeof(*nb_floor)) + return EPT_S_NOT_REGISTERED; + + nb_floor = (const twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*nb_floor); + tower_size -= sizeof(*nb_floor); + + if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) || + (nb_floor->protid != EPM_PROTOCOL_NETBIOS) || + (nb_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + + if (networkaddr) + { + *networkaddr = I_RpcAllocate(nb_floor->count_rhs); + if (!*networkaddr) + { + if (endpoint) + { + I_RpcFree(*endpoint); + *endpoint = NULL; + } + return RPC_S_OUT_OF_RESOURCES; + } + memcpy(*networkaddr, tower_data, nb_floor->count_rhs); + } + + return RPC_S_OK; +} + +typedef struct _RpcServerProtseq_np +{ + RpcServerProtseq common; + HANDLE mgr_event; +} RpcServerProtseq_np; + +static RpcServerProtseq *rpcrt4_protseq_np_alloc(void) +{ + RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); + if (ps) + ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); + return &ps->common; +} + +static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq) +{ + RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common); + SetEvent(npps->mgr_event); +} + +static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) +{ + HANDLE *objs = prev_array; + RpcConnection_np *conn; + RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common); + + EnterCriticalSection(&protseq->cs); + + /* open and count connections */ + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common); + while (conn) { + rpcrt4_conn_listen_pipe(conn); + if (conn->ovl.hEvent) + (*count)++; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common); + } + + /* make array of connections */ + if (objs) + objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); + else + objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); + if (!objs) + { + ERR("couldn't allocate objs\n"); + LeaveCriticalSection(&protseq->cs); + return NULL; + } + + objs[0] = npps->mgr_event; + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common); + while (conn) { + if ((objs[*count] = conn->ovl.hEvent)) + (*count)++; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common); + } + LeaveCriticalSection(&protseq->cs); + return objs; +} + +static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array) +{ + HeapFree(GetProcessHeap(), 0, array); +} + +static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) +{ + HANDLE b_handle; + HANDLE *objs = wait_array; + DWORD res; + RpcConnection *cconn; + RpcConnection_np *conn; + + if (!objs) + return -1; + + res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); + 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_np, common); + while (conn) { + if (b_handle == conn->ovl.hEvent) break; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, 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; + } +} + +static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + twr_empty_floor_t *pipe_floor; + size_t size; + size_t endpoint_size; + + TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); + + endpoint_size = strlen(networkaddr) + 1; + size = sizeof(*pipe_floor) + endpoint_size; + + if (!tower_data) + return size; + + pipe_floor = (twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*pipe_floor); + + pipe_floor->count_lhs = sizeof(pipe_floor->protid); + pipe_floor->protid = EPM_PROTOCOL_SMB; + pipe_floor->count_rhs = endpoint_size; + + memcpy(tower_data, endpoint, endpoint_size); + tower_data += endpoint_size; + + return size; +} + +static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data; + + TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); + + *networkaddr = NULL; + *endpoint = NULL; + + if (tower_size < sizeof(*pipe_floor)) + return EPT_S_NOT_REGISTERED; + + tower_data += sizeof(*pipe_floor); + tower_size -= sizeof(*pipe_floor); + + if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) || + (pipe_floor->protid != EPM_PROTOCOL_SMB) || + (pipe_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + + if (endpoint) + { + *endpoint = I_RpcAllocate(pipe_floor->count_rhs); + if (!*endpoint) + return RPC_S_OUT_OF_RESOURCES; + memcpy(*endpoint, tower_data, pipe_floor->count_rhs); + } + + return RPC_S_OK; +} + +/**** ncacn_ip_tcp support ****/ + +typedef struct _RpcConnection_tcp +{ + RpcConnection common; + int sock; +} RpcConnection_tcp; + +static RpcConnection *rpcrt4_conn_tcp_alloc(void) +{ + RpcConnection_tcp *tcpc; + tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp)); + if (tcpc == NULL) + return NULL; + tcpc->sock = -1; + return &tcpc->common; +} + +static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int sock; + int ret; + struct addrinfo *ai; + struct addrinfo *ai_cur; + struct addrinfo hints; + + TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); + + if (tcpc->sock != -1) + return RPC_S_OK; + + hints.ai_flags = 0; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai); + if (ret) + { + ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr, + Connection->Endpoint, gai_strerror(ret)); + return RPC_S_SERVER_UNAVAILABLE; + } + + for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) + { + int val; + + if (TRACE_ON(rpc)) + { + char host[256]; + char service[256]; + getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + TRACE("trying %s:%s\n", host, service); + } + + sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); + if (sock < 0) + { + WARN("socket() failed: %s\n", strerror(errno)); + continue; + } + + if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen)) + { + WARN("connect() failed: %s\n", strerror(errno)); + close(sock); + continue; + } + + /* RPC depends on having minimal latency so disable the Nagle algorithm */ + val = 1; + setsockopt(sock, SOL_TCP, TCP_NODELAY, &val, sizeof(val)); + + tcpc->sock = sock; + + freeaddrinfo(ai); + TRACE("connected\n"); + return RPC_S_OK; + } + + freeaddrinfo(ai); + ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint); + return RPC_S_SERVER_UNAVAILABLE; +} + +static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint) +{ + RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; + int sock; + int ret; + struct addrinfo *ai; + struct addrinfo *ai_cur; + struct addrinfo hints; + RpcConnection *first_connection = NULL; + u_long blocking; + + TRACE("(%p, %s)\n", protseq, endpoint); + + hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(NULL, endpoint, &hints, &ai); + if (ret) + { + ERR("getaddrinfo for port %s failed: %s\n", endpoint, + gai_strerror(ret)); + if ((ret == EAI_SERVICE) || (ret == EAI_NONAME)) + return RPC_S_INVALID_ENDPOINT_FORMAT; + return RPC_S_CANT_CREATE_ENDPOINT; + } + + for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) + { + RpcConnection_tcp *tcpc; + RPC_STATUS create_status; + + if (TRACE_ON(rpc)) + { + char host[256]; + char service[256]; + getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + TRACE("trying %s:%s\n", host, service); + } + + sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); + if (sock < 0) + { + WARN("socket() failed: %s\n", strerror(errno)); + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + + ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen); + if (ret < 0) + { + WARN("bind failed: %s\n", strerror(errno)); + close(sock); + if (errno == WSAEADDRINUSE) + status = RPC_S_DUPLICATE_ENDPOINT; + else + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, + protseq->Protseq, NULL, + endpoint, NULL, NULL, NULL, + NULL); + if (create_status != RPC_S_OK) + { + close(sock); + status = create_status; + continue; + } + + tcpc->sock = sock; + ret = listen(sock, protseq->MaxCalls); + if (ret < 0) + { + WARN("listen failed: %s\n", strerror(errno)); + RPCRT4_DestroyConnection(&tcpc->common); + status = RPC_S_OUT_OF_RESOURCES; + continue; + } + /* need a non-blocking socket, otherwise accept() has a potential + * race-condition (poll() says it is readable, connection drops, + * and accept() blocks until the next connection comes...) + */ + blocking = 1; + ret = ioctlsocket(sock, FIONBIO, &blocking); + if (ret < 0) + { + WARN("couldn't make socket non-blocking, error %d\n", ret); + RPCRT4_DestroyConnection(&tcpc->common); + status = RPC_S_OUT_OF_RESOURCES; + continue; + } + + tcpc->common.Next = first_connection; + first_connection = &tcpc->common; + } + + freeaddrinfo(ai); + + /* if at least one connection was created for an endpoint then + * return success */ + if (first_connection) + { + RpcConnection *conn; + + /* find last element in list */ + for (conn = first_connection; conn->Next; conn = conn->Next) + ; + + EnterCriticalSection(&protseq->cs); + conn->Next = protseq->conn; + protseq->conn = first_connection; + LeaveCriticalSection(&protseq->cs); + + TRACE("listening on %s\n", endpoint); + return RPC_S_OK; + } + + ERR("couldn't listen on port %s\n", endpoint); + return status; +} + +static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + int ret; + struct sockaddr_in address; + socklen_t addrsize; + u_long blocking; + RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; + RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; + + addrsize = sizeof(address); + ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); + if (ret < 0) + { + ERR("Failed to accept a TCP connection: error %d\n", ret); + return RPC_S_OUT_OF_RESOURCES; + } + /* reset to blocking behaviour */ + blocking = 0; + ret = ioctlsocket(ret, FIONBIO, &blocking); + client->sock = ret; + TRACE("Accepted a new TCP connection\n"); + return RPC_S_OK; +} + +static int rpcrt4_conn_tcp_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int r = recv(tcpc->sock, buffer, count, MSG_WAITALL); + TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r); + return r; +} + +static int rpcrt4_conn_tcp_write(RpcConnection *Connection, + const void *buffer, unsigned int count) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int r = write(tcpc->sock, buffer, count); + TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r); + return r; +} + +static int rpcrt4_conn_tcp_close(RpcConnection *Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + + TRACE("%d\n", tcpc->sock); + + if (tcpc->sock != -1) + close(tcpc->sock); + tcpc->sock = -1; + return 0; +} + +static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, + 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); + + 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) +{ +#ifdef FIX_LATER + 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; +#else + return RPC_S_OUT_OF_RESOURCES; +#endif +} + +typedef struct _RpcServerProtseq_sock +{ + RpcServerProtseq common; + int mgr_event_rcv; + int mgr_event_snd; +} RpcServerProtseq_sock; + +static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void) +{ +#ifdef FIX_LATER + RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); + if (ps) + { + int fds[2]; + u_long blocking; + if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds)) + { + blocking = 1; + ioctlsocket(fds[0], FIONBIO, &blocking); + ioctlsocket(fds[1], FIONBIO, &blocking); + ps->mgr_event_rcv = fds[0]; + ps->mgr_event_snd = fds[1]; + } + else + { + ERR("socketpair failed with error %s\n", strerror(errno)); + HeapFree(GetProcessHeap(), 0, ps); + return NULL; + } + } + return &ps->common; +#else + return NULL; +#endif +} + +static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq) +{ + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + char dummy = 1; + write(sockps->mgr_event_snd, &dummy, sizeof(dummy)); +} + +static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) +{ +#ifdef FIX_LATER + struct pollfd *poll_info = prev_array; + RpcConnection_tcp *conn; + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + + EnterCriticalSection(&protseq->cs); + + /* open and count connections */ + *count = 1; + conn = (RpcConnection_tcp *)protseq->conn; + while (conn) { + if (conn->sock != -1) + (*count)++; + conn = (RpcConnection_tcp *)conn->common.Next; + } + + /* make array of connections */ + if (poll_info) + poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, (*count)*sizeof(*poll_info)); + else + poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info)); + if (!poll_info) + { + ERR("couldn't allocate poll_info\n"); + LeaveCriticalSection(&protseq->cs); + return NULL; + } + + poll_info[0].fd = sockps->mgr_event_rcv; + poll_info[0].events = POLLIN; + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) { + if (conn->sock != -1) + { + poll_info[*count].fd = conn->sock; + poll_info[*count].events = POLLIN; + (*count)++; + } + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + LeaveCriticalSection(&protseq->cs); + return poll_info; +#else + return NULL; +#endif +} + +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) +{ +#ifdef FIX_LATER + struct pollfd *poll_info = wait_array; + int ret, i; + RpcConnection *cconn; + RpcConnection_tcp *conn; + + if (!poll_info) + return -1; + + ret = poll(poll_info, count, -1); + if (ret < 0) + { + ERR("poll failed with error %d\n", ret); + return -1; + } + + for (i = 0; i < count; i++) + if (poll_info[i].revents & POLLIN) + { + /* RPC server event */ + if (i == 0) + { + char dummy; + read(poll_info[0].fd, &dummy, sizeof(dummy)); + return 0; + } + + /* find which connection got a RPC */ + EnterCriticalSection(&protseq->cs); + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) { + if (poll_info[i].fd == conn->sock) 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 fd %d\n", poll_info[i].fd); + LeaveCriticalSection(&protseq->cs); + if (cconn) + RPCRT4_new_client(cconn); + else + return -1; + } + + return 1; +#else + return -1; +#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_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_ncalrpc_get_top_of_tower, + rpcrt4_ncalrpc_parse_top_of_tower, + }, + { "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_ncacn_ip_tcp_get_top_of_tower, + rpcrt4_ncacn_ip_tcp_parse_top_of_tower, + } +}; + + +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])) + +const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq) +{ + int i; + for(i=0; iserver); + return Connection->ops->open_connection_client(Connection); +} + +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) +{ + TRACE("(Connection == ^%p)\n", Connection); + if (SecIsValidHandle(&Connection->ctx)) + { + DeleteSecurityContext(&Connection->ctx); + SecInvalidateHandle(&Connection->ctx); + } + rpcrt4_conn_close(Connection); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, + LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, + LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, + RpcBinding* Binding) +{ + const struct connection_ops *ops; + RpcConnection* NewConnection; + + ops = rpcrt4_get_conn_protseq_ops(Protseq); + if (!ops) + { + FIXME("not supported for protseq %s\n", Protseq); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + + NewConnection = ops->alloc(); + NewConnection->Next = NULL; + NewConnection->server = server; + NewConnection->ops = ops; + NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); + NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions); + NewConnection->Used = Binding; + NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; + memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface)); + NewConnection->NextCallId = 1; + + SecInvalidateHandle(&NewConnection->ctx); + memset(&NewConnection->exp, 0, sizeof(NewConnection->exp)); + NewConnection->attr = 0; + if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo); + NewConnection->AuthInfo = AuthInfo; + NewConnection->encryption_auth_len = 0; + NewConnection->signature_auth_len = 0; + if (QOS) RpcQualityOfService_AddRef(QOS); + NewConnection->QOS = QOS; + + list_init(&NewConnection->conn_pool_entry); + + TRACE("connection: %p\n", NewConnection); + *Connection = NewConnection; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCWSTR NetworkOptions, + RpcAssoc **assoc_out) +{ + RpcAssoc *assoc; + + EnterCriticalSection(&assoc_list_cs); + LIST_FOR_EACH_ENTRY(assoc, &assoc_list, RpcAssoc, entry) + { + if (!strcmp(Protseq, assoc->Protseq) && + !strcmp(NetworkAddr, assoc->NetworkAddr) && + !strcmp(Endpoint, assoc->Endpoint) && + ((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions))) + { + assoc->refs++; + *assoc_out = assoc; + LeaveCriticalSection(&assoc_list_cs); + TRACE("using existing assoc %p\n", assoc); + return RPC_S_OK; + } + } + + assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc)); + if (!assoc) + { + LeaveCriticalSection(&assoc_list_cs); + return RPC_S_OUT_OF_RESOURCES; + } + assoc->refs = 1; + list_init(&assoc->connection_pool); + InitializeCriticalSection(&assoc->cs); + assoc->Protseq = RPCRT4_strdupA(Protseq); + assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + assoc->Endpoint = RPCRT4_strdupA(Endpoint); + assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL; + list_add_head(&assoc_list, &assoc->entry); + *assoc_out = assoc; + + LeaveCriticalSection(&assoc_list_cs); + + TRACE("new assoc %p\n", assoc); + + return RPC_S_OK; +} + +ULONG RpcAssoc_Release(RpcAssoc *assoc) +{ + ULONG refs; + + EnterCriticalSection(&assoc_list_cs); + refs = --assoc->refs; + if (!refs) + list_remove(&assoc->entry); + LeaveCriticalSection(&assoc_list_cs); + + if (!refs) + { + RpcConnection *Connection, *cursor2; + + TRACE("destroying assoc %p\n", assoc); + + LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->connection_pool, RpcConnection, conn_pool_entry) + { + list_remove(&Connection->conn_pool_entry); + RPCRT4_DestroyConnection(Connection); + } + + HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions); + HeapFree(GetProcessHeap(), 0, assoc->Endpoint); + HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr); + HeapFree(GetProcessHeap(), 0, assoc->Protseq); + + HeapFree(GetProcessHeap(), 0, assoc); + } + + return refs; +} + +RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo, + const RpcQualityOfService *QOS) +{ + RpcConnection *Connection; + /* try to find a compatible connection from the connection pool */ + EnterCriticalSection(&assoc->cs); + LIST_FOR_EACH_ENTRY(Connection, &assoc->connection_pool, RpcConnection, conn_pool_entry) + if ((Connection->AuthInfo == AuthInfo) && + (Connection->QOS == QOS) && + !memcmp(&Connection->ActiveInterface, InterfaceId, + sizeof(RPC_SYNTAX_IDENTIFIER))) + { + list_remove(&Connection->conn_pool_entry); + LeaveCriticalSection(&assoc->cs); + TRACE("got connection from pool %p\n", Connection); + return Connection; + } + + LeaveCriticalSection(&assoc->cs); + return NULL; +} + +void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection) +{ + assert(!Connection->server); + EnterCriticalSection(&assoc->cs); + list_add_head(&assoc->connection_pool, &Connection->conn_pool_entry); + LeaveCriticalSection(&assoc->cs); +} + + +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) +{ + RPC_STATUS err; + + err = RPCRT4_CreateConnection(Connection, OldConnection->server, + rpcrt4_conn_get_name(OldConnection), + OldConnection->NetworkAddr, + OldConnection->Endpoint, NULL, + OldConnection->AuthInfo, OldConnection->QOS, + NULL); + if (err == RPC_S_OK) + rpcrt4_conn_handoff(OldConnection, *Connection); + return err; +} + +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) +{ + TRACE("connection: %p\n", Connection); + + RPCRT4_CloseConnection(Connection); + RPCRT4_strfree(Connection->Endpoint); + RPCRT4_strfree(Connection->NetworkAddr); + HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions); + if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo); + if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS); + HeapFree(GetProcessHeap(), 0, Connection); + return RPC_S_OK; +} + +RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, + size_t *tower_size, + const char *protseq, + const char *networkaddr, + const char *endpoint) +{ + twr_empty_floor_t *protocol_floor; + const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq); + + *tower_size = 0; + + if (!protseq_ops) + return RPC_S_INVALID_RPC_PROTSEQ; + + if (!tower_data) + { + *tower_size = sizeof(*protocol_floor); + *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint); + return RPC_S_OK; + } + + protocol_floor = (twr_empty_floor_t *)tower_data; + protocol_floor->count_lhs = sizeof(protocol_floor->protid); + protocol_floor->protid = protseq_ops->epm_protocols[0]; + protocol_floor->count_rhs = 0; + + tower_data += sizeof(*protocol_floor); + + *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint); + if (!*tower_size) + return EPT_S_NOT_REGISTERED; + + *tower_size += sizeof(*protocol_floor); + + return RPC_S_OK; +} + +RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, + size_t tower_size, + char **protseq, + char **networkaddr, + char **endpoint) +{ + const twr_empty_floor_t *protocol_floor; + const twr_empty_floor_t *floor4; + const struct connection_ops *protseq_ops = NULL; + RPC_STATUS status; + int i; + + if (tower_size < sizeof(*protocol_floor)) + return EPT_S_NOT_REGISTERED; + + protocol_floor = (const twr_empty_floor_t *)tower_data; + tower_data += sizeof(*protocol_floor); + tower_size -= sizeof(*protocol_floor); + if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) || + (protocol_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + tower_data += protocol_floor->count_rhs; + tower_size -= protocol_floor->count_rhs; + + floor4 = (const twr_empty_floor_t *)tower_data; + if ((tower_size < sizeof(*floor4)) || + (floor4->count_lhs != sizeof(floor4->protid))) + return EPT_S_NOT_REGISTERED; + + for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++) + if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) && + (floor4->protid == conn_protseq_list[i].epm_protocols[1])) + { + protseq_ops = &conn_protseq_list[i]; + break; + } + + if (!protseq_ops) + return EPT_S_NOT_REGISTERED; + + status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint); + + if ((status == RPC_S_OK) && protseq) + { + *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1); + strcpy(*protseq, protseq_ops->name); + } + + return status; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidW (RPCRT4.@) + * + * Checks if the given protocol sequence is known by the RPC system. + * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. + * + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq) +{ + char ps[0x10]; + + WideCharToMultiByte(CP_ACP, 0, protseq, -1, + ps, sizeof ps, NULL, NULL); + if (rpcrt4_get_conn_protseq_ops(ps)) + return RPC_S_OK; + + FIXME("Unknown protseq %s\n", debugstr_w(protseq)); + + return RPC_S_INVALID_RPC_PROTSEQ; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq) +{ + UNICODE_STRING protseqW; + + if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq)) + { + RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); + RtlFreeUnicodeString(&protseqW); + return ret; + } + return RPC_S_OUT_OF_MEMORY; +} diff --git a/reactos/dll/win32/rpcrt4/rpcrt4.rbuild b/reactos/dll/win32/rpcrt4/rpcrt4.rbuild index 515c20d83cd..bcbe3967295 100644 --- a/reactos/dll/win32/rpcrt4/rpcrt4.rbuild +++ b/reactos/dll/win32/rpcrt4/rpcrt4.rbuild @@ -17,19 +17,22 @@ ntdll kernel32 advapi32 + secur32 iphlpapi + ws2_32 cproxy.c cpsf.c cstub.c + ndr_clientserver.c + ndr_fullpointer.c ndr_marshall.c - ndr_midl.c ndr_ole.c ndr_stubless.c rpc_binding.c rpc_epmap.c rpc_message.c rpc_server.c - ndr_contexth.c + rpc_transport.c rpcrt4_main.c rpcss_np_client.c rpcrt4.rc diff --git a/reactos/dll/win32/rpcrt4/rpcrt4.spec b/reactos/dll/win32/rpcrt4/rpcrt4.spec index de4df2eb758..c5498d7037a 100644 --- a/reactos/dll/win32/rpcrt4/rpcrt4.spec +++ b/reactos/dll/win32/rpcrt4/rpcrt4.spec @@ -19,7 +19,7 @@ @ stdcall IUnknown_QueryInterface_Proxy(ptr ptr ptr) @ stdcall IUnknown_Release_Proxy(ptr) @ stub I_RpcAbortAsyncCall -@ stub I_RpcAllocate +@ stdcall I_RpcAllocate(long) @ stub I_RpcAsyncAbortCall @ stub I_RpcAsyncSendReceive # NT4 @ stub I_RpcAsyncSetHandle @@ -45,7 +45,7 @@ @ stub I_RpcDeleteMutex @ stub I_RpcEnableWmiTrace # wxp @ stub I_RpcExceptionFilter # wxp -@ stub I_RpcFree +@ stdcall I_RpcFree(ptr) @ stdcall I_RpcFreeBuffer(ptr) @ stub I_RpcFreePipeBuffer @ stub I_RpcGetAssociationContext @@ -59,7 +59,7 @@ @ stub I_RpcIfInqTransferSyntaxes @ stub I_RpcLaunchDatagramReceiveThread # win9x @ stub I_RpcLogEvent -@ stub I_RpcMapWin32Status +@ stdcall I_RpcMapWin32Status(long) @ stub I_RpcMonitorAssociation @ stub I_RpcNegotiateTransferSyntax # wxp @ stub I_RpcNsBindingSetEntryName @@ -140,12 +140,12 @@ @ stdcall NDRCContextBinding(ptr) @ stdcall NDRCContextMarshall(ptr ptr) @ stdcall NDRCContextUnmarshall(ptr ptr ptr long) -@ stub NDRSContextMarshall2 +@ stdcall NDRSContextMarshall2(ptr ptr ptr ptr ptr long) @ stdcall NDRSContextMarshall(ptr ptr ptr) @ stdcall NDRSContextMarshallEx(ptr ptr ptr ptr) -@ stub NDRSContextUnmarshall2 -@ stdcall NDRSContextUnmarshall(ptr long) -@ stdcall NDRSContextUnmarshallEx(ptr ptr long) +@ stdcall NDRSContextUnmarshall2(ptr ptr ptr ptr long) +@ stdcall NDRSContextUnmarshall(ptr ptr) +@ stdcall NDRSContextUnmarshallEx(ptr ptr ptr) @ stub NDRcopy @ stdcall NdrAllocate(ptr long) @ stub NdrAsyncClientCall @@ -158,7 +158,7 @@ @ stdcall NdrCStdStubBuffer_Release(ptr ptr) @ stdcall NdrClearOutParameters(ptr ptr ptr) @ varargs NdrClientCall2(ptr ptr) -@ stub NdrClientCall +@ varargs NdrClientCall(ptr ptr) NdrClientCall2 @ stdcall NdrClientContextMarshall(ptr ptr long) @ stdcall NdrClientContextUnmarshall(ptr ptr ptr) @ stub NdrClientInitialize @@ -221,12 +221,12 @@ @ stdcall NdrFixedArrayMemorySize(ptr ptr) @ stdcall NdrFixedArrayUnmarshall(ptr ptr ptr long) @ stdcall NdrFreeBuffer(ptr) -@ stub NdrFullPointerFree -@ stub NdrFullPointerInsertRefId -@ stub NdrFullPointerQueryPointer -@ stub NdrFullPointerQueryRefId -@ stub NdrFullPointerXlatFree -@ stub NdrFullPointerXlatInit +@ stdcall NdrFullPointerFree(ptr ptr) +@ stdcall NdrFullPointerInsertRefId(ptr long ptr) +@ stdcall NdrFullPointerQueryPointer(ptr ptr long ptr) +@ stdcall NdrFullPointerQueryRefId(ptr long long ptr) +@ stdcall NdrFullPointerXlatFree(ptr) +@ stdcall NdrFullPointerXlatInit(long long) @ stdcall NdrGetBuffer(ptr long ptr) @ stub NdrGetDcomProtocolVersion @ stub NdrGetPartialBuffer @@ -377,20 +377,20 @@ @ stub RpcBindingInqAuthClientExA @ stub RpcBindingInqAuthClientExW @ stub RpcBindingInqAuthClientW -@ stub RpcBindingInqAuthInfoA -@ stub RpcBindingInqAuthInfoExA -@ stub RpcBindingInqAuthInfoExW -@ stub RpcBindingInqAuthInfoW +@ stdcall RpcBindingInqAuthInfoA(ptr ptr ptr ptr ptr ptr) +@ stdcall RpcBindingInqAuthInfoExA(ptr ptr ptr ptr ptr ptr long ptr) +@ stdcall RpcBindingInqAuthInfoExW(ptr ptr ptr ptr ptr ptr long ptr) +@ stdcall RpcBindingInqAuthInfoW(ptr ptr ptr ptr ptr ptr) @ stdcall RpcBindingInqObject(ptr ptr) @ stub RpcBindingInqOption @ stub RpcBindingReset @ stub RpcBindingServerFromClient -@ stub RpcBindingSetAuthInfoA -@ stub RpcBindingSetAuthInfoExA -@ stub RpcBindingSetAuthInfoExW -@ stub RpcBindingSetAuthInfoW +@ stdcall RpcBindingSetAuthInfoA(ptr str long long ptr long) +@ stdcall RpcBindingSetAuthInfoExA(ptr str long long ptr long ptr) +@ stdcall RpcBindingSetAuthInfoExW(ptr wstr long long ptr long ptr) +@ stdcall RpcBindingSetAuthInfoW(ptr wstr long long ptr long) @ stdcall RpcBindingSetObject(ptr ptr) -@ stub RpcBindingSetOption +@ stdcall RpcBindingSetOption(ptr long long) @ stdcall RpcBindingToStringBindingA(ptr ptr) @ stdcall RpcBindingToStringBindingW(ptr ptr) @ stdcall RpcBindingVectorFree(ptr) @@ -423,25 +423,25 @@ @ stub RpcInitializeAsyncHandle @ stub RpcMgmtBindingInqParameter # win9x @ stub RpcMgmtBindingSetParameter # win9x -@ stub RpcMgmtEnableIdleCleanup -@ stub RpcMgmtEpEltInqBegin +@ stdcall RpcMgmtEnableIdleCleanup() +@ stdcall RpcMgmtEpEltInqBegin(ptr long ptr long ptr ptr) @ stub RpcMgmtEpEltInqDone @ stub RpcMgmtEpEltInqNextA @ stub RpcMgmtEpEltInqNextW @ stub RpcMgmtEpUnregister @ stub RpcMgmtInqComTimeout @ stub RpcMgmtInqDefaultProtectLevel -@ stub RpcMgmtInqIfIds +@ stdcall RpcMgmtInqIfIds(ptr ptr) @ stub RpcMgmtInqParameter # win9x @ stub RpcMgmtInqServerPrincNameA @ stub RpcMgmtInqServerPrincNameW @ stub RpcMgmtInqStats -@ stub RpcMgmtIsServerListening +@ stdcall RpcMgmtIsServerListening(ptr) @ stub RpcMgmtSetAuthorizationFn @ stub RpcMgmtSetCancelTimeout -@ stub RpcMgmtSetComTimeout +@ stdcall RpcMgmtSetComTimeout(ptr long) @ stub RpcMgmtSetParameter # win9x -@ stub RpcMgmtSetServerStackSize +@ stdcall RpcMgmtSetServerStackSize(long) @ stub RpcMgmtStatsVectorFree @ stdcall RpcMgmtStopServerListening(ptr) @ stdcall RpcMgmtWaitServerListen() @@ -494,7 +494,7 @@ @ stub RpcServerYield @ stub RpcSmAllocate @ stub RpcSmClientFree -@ stdcall RpcSmDestroyClientContext (ptr) +@ stub RpcSmDestroyClientContext @ stub RpcSmDisableAllocate @ stub RpcSmEnableAllocate @ stub RpcSmFree @@ -505,7 +505,7 @@ @ stub RpcSsAllocate @ stub RpcSsContextLockExclusive # wxp @ stub RpcSsContextLockShared # wxp -@ stdcall RpcSsDestroyClientContext (ptr) +@ stub RpcSsDestroyClientContext @ stub RpcSsDisableAllocate @ stub RpcSsDontSerializeContext @ stub RpcSsEnableAllocate @@ -527,8 +527,8 @@ @ stub SimpleTypeBufferSize # wxp @ stub SimpleTypeMemorySize # wxp @ stub StartServiceIfNecessary # win9x -@ stub TowerConstruct -@ stub TowerExplode +@ stdcall TowerConstruct(ptr ptr ptr ptr ptr ptr) +@ stdcall TowerExplode(ptr ptr ptr ptr ptr ptr) @ stdcall UuidCompare(ptr ptr ptr) @ stdcall UuidCreate(ptr) @ stdcall UuidCreateNil(ptr) diff --git a/reactos/dll/win32/rpcrt4/rpcrt4_main.c b/reactos/dll/win32/rpcrt4/rpcrt4_main.c index 0b8e1e032e6..513ff472054 100644 --- a/reactos/dll/win32/rpcrt4/rpcrt4_main.c +++ b/reactos/dll/win32/rpcrt4/rpcrt4_main.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * WINE RPC TODO's (and a few TODONT's) * @@ -152,6 +152,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME); + if (!master_mutex) + ERR("Failed to create master mutex\n"); break; case DLL_PROCESS_DETACH: @@ -172,7 +174,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) * * S_OK if successful. */ -RPC_STATUS WINAPI RpcStringFreeA(unsigned char** String) +RPC_STATUS WINAPI RpcStringFreeA(RPC_CSTR* String) { HeapFree( GetProcessHeap(), 0, *String); @@ -188,7 +190,7 @@ RPC_STATUS WINAPI RpcStringFreeA(unsigned char** String) * * S_OK if successful. */ -RPC_STATUS WINAPI RpcStringFreeW(unsigned short** String) +RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR* String) { HeapFree( GetProcessHeap(), 0, *String); @@ -319,8 +321,6 @@ static void RPC_UuidGetSystemTime(ULONGLONG *time) *time += TICKS_15_OCT_1582_TO_1601; } -typedef DWORD WINAPI (*LPGETADAPTERSINFO)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); - /* Assume that a hardware address is at least 6 bytes long */ #define ADDRESS_BYTES_NEEDED 6 @@ -331,46 +331,28 @@ static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) ULONG buflen = sizeof(IP_ADAPTER_INFO); PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - HANDLE hIpHlpApi; - LPGETADAPTERSINFO pGetAdaptersInfo; - - hIpHlpApi = LoadLibrary("iphlpapi.dll"); - if (hIpHlpApi) - { - pGetAdaptersInfo = (LPGETADAPTERSINFO)GetProcAddress(hIpHlpApi, "GetAdaptersInfo"); - if (pGetAdaptersInfo) - { - if (pGetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { - HeapFree(GetProcessHeap(), 0, adapter); - adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - } - if (pGetAdaptersInfo(adapter, &buflen) == NO_ERROR) { - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = adapter->Address[i]; - } - } - else - { - goto local; - } + 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]; } - - /* Free the Library */ - FreeLibrary(hIpHlpApi); - goto exit; } - -local: /* We can't get a hardware address, just use random numbers. - Set the multicast bit to prevent conflicts with real cards. */ - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = rand() & 0xff; + 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; } - address[0] |= 0x01; - status = RPC_S_UUID_LOCAL_ONLY; - -exit: + HeapFree(GetProcessHeap(), 0, adapter); return status; } @@ -525,9 +507,9 @@ unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status) * RETURNS * * S_OK if successful. - * S_OUT_OF_MEMORY if unsucessful. + * S_OUT_OF_MEMORY if unsuccessful. */ -RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, unsigned char** StringUuid) +RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, RPC_CSTR* StringUuid) { *StringUuid = HeapAlloc( GetProcessHeap(), 0, sizeof(char) * 37); @@ -536,7 +518,7 @@ RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, unsigned char** StringUuid) if (!Uuid) Uuid = &uuid_nil; - sprintf( (char*)*StringUuid, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + sprintf( (char*)*StringUuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", Uuid->Data1, Uuid->Data2, Uuid->Data3, Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], @@ -551,15 +533,15 @@ RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, unsigned char** StringUuid) * Converts a UUID to a string. * * S_OK if successful. - * S_OUT_OF_MEMORY if unsucessful. + * S_OUT_OF_MEMORY if unsuccessful. */ -RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, unsigned short** StringUuid) +RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, RPC_WSTR* StringUuid) { char buf[37]; if (!Uuid) Uuid = &uuid_nil; - sprintf(buf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", Uuid->Data1, Uuid->Data2, Uuid->Data3, Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], @@ -587,7 +569,7 @@ static const BYTE hex2bin[] = /*********************************************************************** * UuidFromStringA (RPCRT4.@) */ -RPC_STATUS WINAPI UuidFromStringA(unsigned char* s, UUID *uuid) +RPC_STATUS WINAPI UuidFromStringA(RPC_CSTR s, UUID *uuid) { int i; @@ -627,7 +609,7 @@ RPC_STATUS WINAPI UuidFromStringA(unsigned char* s, UUID *uuid) /*********************************************************************** * UuidFromStringW (RPCRT4.@) */ -RPC_STATUS WINAPI UuidFromStringW(unsigned short* s, UUID *uuid) +RPC_STATUS WINAPI UuidFromStringW(RPC_WSTR s, UUID *uuid) { int i; @@ -673,8 +655,8 @@ HRESULT WINAPI DllRegisterServer( void ) return S_OK; } -BOOL RPCRT4_StartRPCSS(void) -{ +static BOOL RPCRT4_StartRPCSS(void) +{ PROCESS_INFORMATION pi; STARTUPINFOA si; static char cmd[6]; @@ -728,13 +710,14 @@ BOOL RPCRT4_StartRPCSS(void) BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply) { HANDLE client_handle; + BOOL ret; int i, j = 0; TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply); client_handle = RPCRT4_RpcssNPConnect(); - while (!client_handle) { + while (INVALID_HANDLE_VALUE == client_handle) { /* start the RPCSS process */ if (!RPCRT4_StartRPCSS()) { ERR("Unable to start RPCSS process.\n"); @@ -744,13 +727,13 @@ BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPC for (i = 0; i < 60; i++) { Sleep(200); client_handle = RPCRT4_RpcssNPConnect(); - if (client_handle) break; + if (INVALID_HANDLE_VALUE != client_handle) break; } /* we are only willing to try twice */ if (j++ >= 1) break; } - if (!client_handle) { + if (INVALID_HANDLE_VALUE == client_handle) { /* no dice! */ ERR("Unable to connect to RPCSS process!\n"); SetLastError(RPC_E_SERVER_DIED_DNE); @@ -758,12 +741,14 @@ BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPC } /* great, we're connected. now send the message */ + ret = TRUE; if (!RPCRT4_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) { ERR("Something is amiss: RPC_SendReceive failed.\n"); - return FALSE; + ret = FALSE; } + CloseHandle(client_handle); - return TRUE; + return ret; } #define MAX_RPC_ERROR_TEXT 256 @@ -780,7 +765,7 @@ BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPC * 4. The MSDN documentation currently declares that the second argument is * unsigned char *, even for the W version. I don't believe it. */ -RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, unsigned short *buffer) +RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, RPC_WSTR buffer) { DWORD count; count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | @@ -793,7 +778,7 @@ RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, unsigned short *buffer) NULL, RPC_S_NOT_RPC_ERROR, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); if (!count) { - ERR ("Failed to translate error"); + ERR ("Failed to translate error\n"); return RPC_S_INVALID_ARG; } } @@ -803,7 +788,7 @@ RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, unsigned short *buffer) /****************************************************************************** * DceErrorInqTextA (rpcrt4.@) */ -RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, unsigned char *buffer) +RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, RPC_CSTR buffer) { RPC_STATUS status; WCHAR bufferW [MAX_RPC_ERROR_TEXT]; @@ -812,9 +797,34 @@ RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, unsigned char *buffer) if (!WideCharToMultiByte(CP_ACP, 0, bufferW, -1, (LPSTR)buffer, MAX_RPC_ERROR_TEXT, NULL, NULL)) { - ERR ("Failed to translate error"); + ERR ("Failed to translate error\n"); status = RPC_S_INVALID_ARG; } } return status; } + +/****************************************************************************** + * I_RpcAllocate (rpcrt4.@) + */ +void * WINAPI I_RpcAllocate(unsigned int Size) +{ + return HeapAlloc(GetProcessHeap(), 0, Size); +} + +/****************************************************************************** + * I_RpcFree (rpcrt4.@) + */ +void WINAPI I_RpcFree(void *Object) +{ + HeapFree(GetProcessHeap(), 0, Object); +} + +/****************************************************************************** + * I_RpcMapWin32Status (rpcrt4.@) + */ +DWORD WINAPI I_RpcMapWin32Status(RPC_STATUS status) +{ + FIXME("(%ld): stub\n", status); + return 0; +} diff --git a/reactos/dll/win32/rpcrt4/rpcss_np_client.c b/reactos/dll/win32/rpcrt4/rpcss_np_client.c index 3906f212999..016f77f5f15 100644 --- a/reactos/dll/win32/rpcrt4/rpcss_np_client.c +++ b/reactos/dll/win32/rpcrt4/rpcss_np_client.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -32,7 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); HANDLE RPCRT4_RpcssNPConnect(void) { - HANDLE the_pipe = NULL; + HANDLE the_pipe; DWORD dwmode, wait_result; HANDLE master_mutex = RPCRT4_GetMasterMutex(); @@ -69,7 +69,6 @@ HANDLE RPCRT4_RpcssNPConnect(void) if (GetLastError() != ERROR_PIPE_BUSY) { WARN("Unable to open named pipe %s (assuming unavailable).\n", debugstr_a(NAME_RPCSS_NAMED_PIPE)); - the_pipe = NULL; break; } @@ -78,18 +77,17 @@ HANDLE RPCRT4_RpcssNPConnect(void) if (!ReleaseMutex(master_mutex)) ERR("Failed to release master mutex. Expect deadlock.\n"); - /* wait for the named pipe. We are only - willing to wait only 5 seconds. It should be available /very/ soon. */ + /* wait for the named pipe. We are only willing to wait for 5 seconds. + It should be available /very/ soon. */ if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT)) { ERR("Named pipe unavailable after waiting. Something is probably wrong.\n"); - the_pipe = NULL; break; } } - if (the_pipe) { + if (the_pipe != INVALID_HANDLE_VALUE) { dwmode = PIPE_READMODE_MESSAGE; /* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */ if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL)) @@ -145,7 +143,7 @@ BOOL RPCRT4_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PR } if (count != sizeof(RPCSS_NP_REPLY)) { - ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY)); + ERR("read count mismatch. got %d.\n", count); return FALSE; } diff --git a/reactos/dll/win32/rpcrt4/rpcss_np_client.h b/reactos/dll/win32/rpcrt4/rpcss_np_client.h index c50e8ada80f..db65d432bca 100644 --- a/reactos/dll/win32/rpcrt4/rpcss_np_client.h +++ b/reactos/dll/win32/rpcrt4/rpcss_np_client.h @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_RPCSS_NP_CLIENT_H diff --git a/reactos/include/psdk/rpc.h b/reactos/include/psdk/rpc.h index d4687760e75..aebd76ed178 100644 --- a/reactos/include/psdk/rpc.h +++ b/reactos/include/psdk/rpc.h @@ -69,6 +69,6 @@ typedef void* I_RPC_HANDLE; RPC_STATUS RPC_ENTRY RpcImpersonateClient(RPC_BINDING_HANDLE); RPC_STATUS RPC_ENTRY RpcRevertToSelf(void); -long RPC_ENTRY I_RpcMapWin32Status(RPC_STATUS); +DWORD WINAPI I_RpcMapWin32Status(RPC_STATUS status); #endif /*__WINE_RPC_H */ diff --git a/reactos/include/psdk/sspi.h b/reactos/include/psdk/sspi.h index 369d5ea0ce1..c7f44e365c2 100644 --- a/reactos/include/psdk/sspi.h +++ b/reactos/include/psdk/sspi.h @@ -62,7 +62,7 @@ typedef struct _SecHandle #define SecInvalidateHandle(x) do { \ ((PSecHandle)(x))->dwLower = ((ULONG_PTR)((INT_PTR)-1)); \ ((PSecHandle)(x))->dwUpper = ((ULONG_PTR)((INT_PTR)-1)); \ - while (0) + } while (0) #define SecIsValidHandle(x) \ ((((PSecHandle)(x))->dwLower != ((ULONG_PTR)(INT_PTR)-1)) && \ @@ -238,6 +238,9 @@ typedef SECURITY_STATUS (SEC_ENTRY *FREE_CONTEXT_BUFFER_FN)(PVOID); SECURITY_STATUS SEC_ENTRY FreeCredentialsHandle(PCredHandle phCredential); + +#define FreeCredentialHandle FreeCredentialsHandle + typedef SECURITY_STATUS (SEC_ENTRY *FREE_CREDENTIALS_HANDLE_FN)(PCredHandle); SECURITY_STATUS SEC_ENTRY InitializeSecurityContextA( diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index 7eeae6dded8..0b7035ad2cb 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -72,7 +72,7 @@ reactos/dll/win32/olepro32 # Autosync reactos/dll/win32/powrprof # Synced to Wine-0_9_14 reactos/dll/win32/riched20 # Synced to Wine-0_9_5 reactos/dll/win32/riched32 # Autosync -reactos/dll/win32/rpcrt4 # Synced to Wine-0_9_10 +reactos/dll/win32/rpcrt4 # Synced to Wine-20070507 reactos/dll/win32/sensapi # Autosync reactos/dll/win32/setupapi # Forked at Wine-20050524 reactos/dll/win32/shell32 # Synced to Wine-0_9_5