-/*\r
- * RPC server API\r
- *\r
- * Copyright 2001 Ove Kåven, TransGaming Technologies\r
- * Copyright 2004 Filip Navara\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- *\r
- * TODO:\r
- * - a whole lot\r
- */\r
-\r
-#include "config.h"\r
-#include "wine/port.h"\r
-\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <assert.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winerror.h"\r
-#include "winreg.h"\r
-#include "ntstatus.h"\r
-\r
-#include "rpc.h"\r
-#include "rpcndr.h"\r
-#include "excpt.h"\r
-\r
-#include "wine/debug.h"\r
-#include "wine/exception.h"\r
-\r
-#include "rpc_server.h"\r
-#include "rpc_misc.h"\r
-#include "rpc_message.h"\r
-#include "rpc_defs.h"\r
-\r
-#define MAX_THREADS 128\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-\r
-typedef struct _RpcPacket\r
-{\r
- struct _RpcPacket* next;\r
- struct _RpcConnection* conn;\r
- RpcPktHdr* hdr;\r
- RPC_MESSAGE* msg;\r
-} RpcPacket;\r
-\r
-typedef struct _RpcObjTypeMap\r
-{\r
- /* FIXME: a hash table would be better. */\r
- struct _RpcObjTypeMap *next;\r
- UUID Object;\r
- UUID Type;\r
-} RpcObjTypeMap;\r
-\r
-static RpcObjTypeMap *RpcObjTypeMaps;\r
-\r
-static RpcServerProtseq* protseqs;\r
-static RpcServerInterface* ifs;\r
-\r
-static CRITICAL_SECTION server_cs;\r
-static CRITICAL_SECTION_DEBUG server_cs_debug =\r
-{\r
- 0, 0, &server_cs,\r
- { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },\r
- 0, 0, { 0, (DWORD)(__FILE__ ": server_cs") }\r
-};\r
-static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };\r
-\r
-static CRITICAL_SECTION listen_cs;\r
-static CRITICAL_SECTION_DEBUG listen_cs_debug =\r
-{\r
- 0, 0, &listen_cs,\r
- { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },\r
- 0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") }\r
-};\r
-static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };\r
-\r
-static BOOL std_listen;\r
-static LONG listen_count = -1;\r
-static HANDLE mgr_event, server_thread;\r
-\r
-static CRITICAL_SECTION spacket_cs;\r
-static CRITICAL_SECTION_DEBUG spacket_cs_debug =\r
-{\r
- 0, 0, &spacket_cs,\r
- { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList },\r
- 0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") }\r
-};\r
-static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 };\r
-\r
-static RpcPacket* spacket_head;\r
-static RpcPacket* spacket_tail;\r
-static HANDLE server_sem;\r
-\r
-static DWORD worker_count, worker_free, worker_tls;\r
-\r
-static UUID uuid_nil;\r
-\r
-inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)\r
-{\r
- RpcObjTypeMap *rslt = RpcObjTypeMaps;\r
- RPC_STATUS dummy;\r
-\r
- while (rslt) {\r
- if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;\r
- rslt = rslt->next;\r
- }\r
-\r
- return rslt;\r
-}\r
-\r
-inline static UUID *LookupObjType(UUID *ObjUuid)\r
-{\r
- RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);\r
- if (map)\r
- return &map->Type;\r
- else\r
- return &uuid_nil;\r
-}\r
-\r
-static RpcServerInterface* RPCRT4_find_interface(UUID* object,\r
- RPC_SYNTAX_IDENTIFIER* if_id,\r
- BOOL check_object)\r
-{\r
- UUID* MgrType = NULL;\r
- RpcServerInterface* cif = NULL;\r
- RPC_STATUS status;\r
-\r
- if (check_object)\r
- MgrType = LookupObjType(object);\r
- EnterCriticalSection(&server_cs);\r
- cif = ifs;\r
- while (cif) {\r
- if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&\r
- (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&\r
- (std_listen || (cif->Flags & RPC_IF_AUTOLISTEN))) break;\r
- cif = cif->Next;\r
- }\r
- LeaveCriticalSection(&server_cs);\r
- TRACE("returning %p for %s\n", cif, debugstr_guid(object));\r
- return cif;\r
-}\r
-\r
-static void RPCRT4_push_packet(RpcPacket* packet)\r
-{\r
- packet->next = NULL;\r
- EnterCriticalSection(&spacket_cs);\r
- if (spacket_tail) {\r
- spacket_tail->next = packet;\r
- spacket_tail = packet;\r
- } else {\r
- spacket_head = packet;\r
- spacket_tail = packet;\r
- }\r
- LeaveCriticalSection(&spacket_cs);\r
-}\r
-\r
-static RpcPacket* RPCRT4_pop_packet(void)\r
-{\r
- RpcPacket* packet;\r
- EnterCriticalSection(&spacket_cs);\r
- packet = spacket_head;\r
- if (packet) {\r
- spacket_head = packet->next;\r
- if (!spacket_head) spacket_tail = NULL;\r
- }\r
- LeaveCriticalSection(&spacket_cs);\r
- if (packet) packet->next = NULL;\r
- return packet;\r
-}\r
-\r
-#ifndef __REACTOS__\r
-typedef struct {\r
- PRPC_MESSAGE msg;\r
- void* buf;\r
-} packet_state;\r
-\r
-static WINE_EXCEPTION_FILTER(rpc_filter)\r
-{\r
- packet_state* state;\r
- PRPC_MESSAGE msg;\r
- state = TlsGetValue(worker_tls);\r
- msg = state->msg;\r
- if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg);\r
- msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION;\r
- msg->BufferLength = sizeof(DWORD);\r
- I_RpcGetBuffer(msg);\r
- *(DWORD*)msg->Buffer = GetExceptionCode();\r
- WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer);\r
- TRACE("returning failure packet\n");\r
- return EXCEPTION_EXECUTE_HANDLER;\r
-}\r
-#endif\r
-\r
-static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg)\r
-{\r
- RpcServerInterface* sif;\r
- RPC_DISPATCH_FUNCTION func;\r
-#ifndef __REACTOS__\r
- packet_state state;\r
-#endif\r
- UUID *object_uuid;\r
- RpcPktHdr *response;\r
- void *buf = msg->Buffer;\r
- RPC_STATUS status;\r
-\r
-#ifndef __REACTOS__\r
- state.msg = msg;\r
- state.buf = buf;\r
- TlsSetValue(worker_tls, &state);\r
-#endif\r
-\r
- switch (hdr->common.ptype) {\r
- case PKT_BIND:\r
- TRACE("got bind packet\n");\r
-\r
- /* FIXME: do more checks! */\r
- if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE ||\r
- !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {\r
- TRACE("packet size less than min size, or active interface syntax guid non-null\n");\r
- sif = NULL;\r
- } else {\r
- sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE);\r
- }\r
- if (sif == NULL) {\r
- TRACE("rejecting bind request on connection %p\n", conn);\r
- /* Report failure to client. */\r
- response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,\r
- RPC_VER_MAJOR, RPC_VER_MINOR);\r
- } else {\r
- TRACE("accepting bind request on connection %p\n", conn);\r
-\r
- /* accept. */\r
- response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,\r
- RPC_MAX_PACKET_SIZE,\r
- RPC_MAX_PACKET_SIZE,\r
- conn->Endpoint,\r
- RESULT_ACCEPT, NO_REASON,\r
- &sif->If->TransferSyntax);\r
-\r
- /* save the interface for later use */\r
- conn->ActiveInterface = hdr->bind.abstract;\r
- conn->MaxTransmissionSize = hdr->bind.max_tsize;\r
- }\r
-\r
- if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK)\r
- goto fail;\r
-\r
- break;\r
-\r
- case PKT_REQUEST:\r
- TRACE("got request packet\n");\r
-\r
- /* fail if the connection isn't bound with an interface */\r
- if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {\r
- response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,\r
- status);\r
-\r
- RPCRT4_Send(conn, response, NULL, 0);\r
- break;\r
- }\r
-\r
- if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {\r
- object_uuid = (UUID*)(&hdr->request + 1);\r
- } else {\r
- object_uuid = NULL;\r
- }\r
-\r
- sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE);\r
- msg->RpcInterfaceInformation = sif->If;\r
- /* copy the endpoint vector from sif to msg so that midl-generated code will use it */\r
- msg->ManagerEpv = sif->MgrEpv;\r
- if (object_uuid != NULL) {\r
- RPCRT4_SetBindingObject(msg->Handle, object_uuid);\r
- }\r
-\r
- /* find dispatch function */\r
- msg->ProcNum = hdr->request.opnum;\r
- if (sif->Flags & RPC_IF_OLE) {\r
- /* native ole32 always gives us a dispatch table with a single entry\r
- * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */\r
- func = *sif->If->DispatchTable->DispatchTable;\r
- } else {\r
- if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {\r
- ERR("invalid procnum\n");\r
- func = NULL;\r
- }\r
- func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];\r
- }\r
-\r
- /* put in the drep. FIXME: is this more universally applicable?\r
- perhaps we should move this outward... */\r
- msg->DataRepresentation = \r
- MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),\r
- MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));\r
-\r
- /* dispatch */\r
-#ifndef __REACTOS__\r
- __TRY {\r
- if (func) func(msg);\r
- } __EXCEPT(rpc_filter) {\r
- /* failure packet was created in rpc_filter */\r
- } __ENDTRY\r
-#else\r
- if (func) func(msg);\r
-#endif\r
-\r
- /* send response packet */\r
- I_RpcSend(msg);\r
-\r
- msg->RpcInterfaceInformation = NULL;\r
-\r
- break;\r
-\r
- default:\r
- FIXME("unhandled packet type\n");\r
- break;\r
- }\r
-\r
-fail:\r
- /* clean up */\r
- if (msg->Buffer == buf) msg->Buffer = NULL;\r
- TRACE("freeing Buffer=%p\n", buf);\r
- HeapFree(GetProcessHeap(), 0, buf);\r
- RPCRT4_DestroyBinding(msg->Handle);\r
- msg->Handle = 0;\r
- I_RpcFreeBuffer(msg);\r
- msg->Buffer = NULL;\r
- RPCRT4_FreeHeader(hdr);\r
-#ifndef __REACTOS__\r
- TlsSetValue(worker_tls, NULL);\r
-#endif\r
-}\r
-\r
-static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)\r
-{\r
- DWORD obj;\r
- RpcPacket* pkt;\r
-\r
- for (;;) {\r
- /* idle timeout after 5s */\r
- obj = WaitForSingleObject(server_sem, 5000);\r
- if (obj == WAIT_TIMEOUT) {\r
- /* if another idle thread exist, self-destruct */\r
- if (worker_free > 1) break;\r
- continue;\r
- }\r
- pkt = RPCRT4_pop_packet();\r
- if (!pkt) continue;\r
- InterlockedDecrement(&worker_free);\r
- for (;;) {\r
- RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg);\r
- HeapFree(GetProcessHeap(), 0, pkt);\r
- /* try to grab another packet here without waiting\r
- * on the semaphore, in case it hits max */\r
- pkt = RPCRT4_pop_packet();\r
- if (!pkt) break;\r
- /* decrement semaphore */\r
- WaitForSingleObject(server_sem, 0);\r
- }\r
- InterlockedIncrement(&worker_free);\r
- }\r
- InterlockedDecrement(&worker_free);\r
- InterlockedDecrement(&worker_count);\r
- return 0;\r
-}\r
-\r
-static void RPCRT4_create_worker_if_needed(void)\r
-{\r
- if (!worker_free && worker_count < MAX_THREADS) {\r
- HANDLE thread;\r
- InterlockedIncrement(&worker_count);\r
- InterlockedIncrement(&worker_free);\r
- thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL);\r
- if (thread) CloseHandle(thread);\r
- else {\r
- InterlockedDecrement(&worker_free);\r
- InterlockedDecrement(&worker_count);\r
- }\r
- }\r
-}\r
-\r
-static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)\r
-{\r
- RpcConnection* conn = (RpcConnection*)the_arg;\r
- RpcPktHdr *hdr;\r
- RpcBinding *pbind;\r
- RPC_MESSAGE *msg;\r
- RPC_STATUS status;\r
- RpcPacket *packet;\r
-\r
- TRACE("(%p)\n", conn);\r
-\r
- for (;;) {\r
- msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));\r
-\r
- /* create temporary binding for dispatch, it will be freed in\r
- * RPCRT4_process_packet */\r
- RPCRT4_MakeBinding(&pbind, conn);\r
- msg->Handle = (RPC_BINDING_HANDLE)pbind;\r
-\r
- status = RPCRT4_Receive(conn, &hdr, msg);\r
- if (status != RPC_S_OK) {\r
- WARN("receive failed with error %lx\n", status);\r
- break;\r
- }\r
-\r
-#if 0\r
- RPCRT4_process_packet(conn, hdr, msg);\r
-#else\r
- packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));\r
- packet->conn = conn;\r
- packet->hdr = hdr;\r
- packet->msg = msg;\r
- RPCRT4_create_worker_if_needed();\r
- RPCRT4_push_packet(packet);\r
- ReleaseSemaphore(server_sem, 1, NULL);\r
-#endif\r
- msg = NULL;\r
- }\r
- HeapFree(GetProcessHeap(), 0, msg);\r
- RPCRT4_DestroyConnection(conn);\r
- return 0;\r
-}\r
-\r
-static void RPCRT4_new_client(RpcConnection* conn)\r
-{\r
- HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);\r
- if (!thread) {\r
- DWORD err = GetLastError();\r
- ERR("failed to create thread, error=%08lx\n", err);\r
- RPCRT4_DestroyConnection(conn);\r
- }\r
- /* we could set conn->thread, but then we'd have to make the io_thread wait\r
- * for that, otherwise the thread might finish, destroy the connection, and\r
- * free the memory we'd write to before we did, causing crashes and stuff -\r
- * so let's implement that later, when we really need conn->thread */\r
-\r
- CloseHandle( thread );\r
-}\r
-\r
-static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)\r
-{\r
- HANDLE m_event = mgr_event, b_handle;\r
- HANDLE *objs = NULL;\r
- DWORD count, res;\r
- RpcServerProtseq* cps;\r
- RpcConnection* conn;\r
- RpcConnection* cconn;\r
-\r
- TRACE("(the_arg == ^%p)\n", the_arg);\r
-\r
- for (;;) {\r
- EnterCriticalSection(&server_cs);\r
- /* open and count connections */\r
- count = 1;\r
- cps = protseqs;\r
- while (cps) {\r
- conn = cps->conn;\r
- while (conn) {\r
- RPCRT4_OpenConnection(conn);\r
- if (conn->ovl.hEvent) count++;\r
- conn = conn->Next;\r
- }\r
- cps = cps->Next;\r
- }\r
- /* make array of connections */\r
- if (objs)\r
- objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE));\r
- else\r
- objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE));\r
-\r
- objs[0] = m_event;\r
- count = 1;\r
- cps = protseqs;\r
- while (cps) {\r
- conn = cps->conn;\r
- while (conn) {\r
- if (conn->ovl.hEvent) objs[count++] = conn->ovl.hEvent;\r
- conn = conn->Next;\r
- }\r
- cps = cps->Next;\r
- }\r
- LeaveCriticalSection(&server_cs);\r
-\r
- /* start waiting */\r
- res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);\r
- if (res == WAIT_OBJECT_0) {\r
- ResetEvent(m_event);\r
- if (!std_listen) break;\r
- }\r
- else if (res == WAIT_FAILED) {\r
- ERR("wait failed\n");\r
- }\r
- else {\r
- b_handle = objs[res - WAIT_OBJECT_0];\r
- /* find which connection got a RPC */\r
- EnterCriticalSection(&server_cs);\r
- conn = NULL;\r
- cps = protseqs;\r
- while (cps) {\r
- conn = cps->conn;\r
- while (conn) {\r
- if (conn->ovl.hEvent == b_handle) break;\r
- conn = conn->Next;\r
- }\r
- if (conn) break;\r
- cps = cps->Next;\r
- }\r
- cconn = NULL;\r
- if (conn) RPCRT4_SpawnConnection(&cconn, conn);\r
- LeaveCriticalSection(&server_cs);\r
- if (!conn) {\r
- ERR("failed to locate connection for handle %p\n", b_handle);\r
- }\r
- if (cconn) RPCRT4_new_client(cconn);\r
- }\r
- }\r
- HeapFree(GetProcessHeap(), 0, objs);\r
- EnterCriticalSection(&server_cs);\r
- /* close connections */\r
- cps = protseqs;\r
- while (cps) {\r
- conn = cps->conn;\r
- while (conn) {\r
- RPCRT4_CloseConnection(conn);\r
- conn = conn->Next;\r
- }\r
- cps = cps->Next;\r
- }\r
- LeaveCriticalSection(&server_cs);\r
- return 0;\r
-}\r
-\r
-static void RPCRT4_start_listen(void)\r
-{\r
- TRACE("\n");\r
-\r
- EnterCriticalSection(&listen_cs);\r
- if (! ++listen_count) {\r
- if (!mgr_event) mgr_event = CreateEventW(NULL, TRUE, FALSE, NULL);\r
- if (!server_sem) server_sem = CreateSemaphoreW(NULL, 0, MAX_THREADS, NULL);\r
- if (!worker_tls) worker_tls = TlsAlloc();\r
- std_listen = TRUE;\r
- server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);\r
- LeaveCriticalSection(&listen_cs);\r
- } else {\r
- LeaveCriticalSection(&listen_cs);\r
- SetEvent(mgr_event);\r
- }\r
-}\r
-\r
-static void RPCRT4_stop_listen(void)\r
-{\r
- EnterCriticalSection(&listen_cs);\r
- if (listen_count == -1)\r
- LeaveCriticalSection(&listen_cs);\r
- else if (--listen_count == -1) {\r
- std_listen = FALSE;\r
- LeaveCriticalSection(&listen_cs);\r
- SetEvent(mgr_event);\r
- } else\r
- LeaveCriticalSection(&listen_cs);\r
- assert(listen_count > -2);\r
-}\r
-\r
-static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)\r
-{\r
- RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL);\r
-\r
- EnterCriticalSection(&server_cs);\r
- ps->Next = protseqs;\r
- protseqs = ps;\r
- LeaveCriticalSection(&server_cs);\r
-\r
- if (std_listen) SetEvent(mgr_event);\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerInqBindings (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )\r
-{\r
- RPC_STATUS status;\r
- DWORD count;\r
- RpcServerProtseq* ps;\r
- RpcConnection* conn;\r
-\r
- if (BindingVector)\r
- TRACE("(*BindingVector == ^%p)\n", *BindingVector);\r
- else\r
- ERR("(BindingVector == NULL!!?)\n");\r
-\r
- EnterCriticalSection(&server_cs);\r
- /* count connections */\r
- count = 0;\r
- ps = protseqs;\r
- while (ps) {\r
- conn = ps->conn;\r
- while (conn) {\r
- count++;\r
- conn = conn->Next;\r
- }\r
- ps = ps->Next;\r
- }\r
- if (count) {\r
- /* export bindings */\r
- *BindingVector = HeapAlloc(GetProcessHeap(), 0,\r
- sizeof(RPC_BINDING_VECTOR) +\r
- sizeof(RPC_BINDING_HANDLE)*(count-1));\r
- (*BindingVector)->Count = count;\r
- count = 0;\r
- ps = protseqs;\r
- while (ps) {\r
- conn = ps->conn;\r
- while (conn) {\r
- RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],\r
- conn);\r
- count++;\r
- conn = conn->Next;\r
- }\r
- ps = ps->Next;\r
- }\r
- status = RPC_S_OK;\r
- } else {\r
- *BindingVector = NULL;\r
- status = RPC_S_NO_BINDINGS;\r
- }\r
- LeaveCriticalSection(&server_cs);\r
- return status;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUseProtseqEpA (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor )\r
-{\r
- RPC_POLICY policy;\r
- \r
- TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );\r
- \r
- /* This should provide the default behaviour */\r
- policy.Length = sizeof( policy );\r
- policy.EndpointFlags = 0;\r
- policy.NICFlags = 0;\r
- \r
- return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUseProtseqEpW (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )\r
-{\r
- RPC_POLICY policy;\r
- \r
- TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );\r
- \r
- /* This should provide the default behaviour */\r
- policy.Length = sizeof( policy );\r
- policy.EndpointFlags = 0;\r
- policy.NICFlags = 0;\r
- \r
- return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUseProtseqEpExA (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor,\r
- PRPC_POLICY lpPolicy )\r
-{\r
- RpcServerProtseq* ps;\r
-\r
- TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( Protseq ), MaxCalls,\r
- debugstr_a( Endpoint ), SecurityDescriptor,\r
- lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );\r
-\r
- ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));\r
- ps->MaxCalls = MaxCalls;\r
- ps->Protseq = RPCRT4_strdupA(Protseq);\r
- ps->Endpoint = RPCRT4_strdupA(Endpoint);\r
-\r
- return RPCRT4_use_protseq(ps);\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUseProtseqEpExW (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,\r
- PRPC_POLICY lpPolicy )\r
-{\r
- RpcServerProtseq* ps;\r
-\r
- TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls,\r
- debugstr_w( Endpoint ), SecurityDescriptor,\r
- lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );\r
-\r
- ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq));\r
- ps->MaxCalls = MaxCalls;\r
- ps->Protseq = RPCRT4_strdupWtoA(Protseq);\r
- ps->Endpoint = RPCRT4_strdupWtoA(Endpoint);\r
-\r
- return RPCRT4_use_protseq(ps);\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUseProtseqA (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor)\r
-{\r
- TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a(Protseq), MaxCalls, SecurityDescriptor);\r
- return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor);\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUseProtseqW (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)\r
-{\r
- TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);\r
- return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor);\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerRegisterIf (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )\r
-{\r
- TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);\r
- return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerRegisterIfEx (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,\r
- UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )\r
-{\r
- TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);\r
- return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerRegisterIf2 (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,\r
- UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )\r
-{\r
- PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;\r
- RpcServerInterface* sif;\r
- unsigned int i;\r
-\r
- TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,\r
- MaxRpcSize, IfCallbackFn);\r
- TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),\r
- If->InterfaceId.SyntaxVersion.MajorVersion,\r
- If->InterfaceId.SyntaxVersion.MinorVersion);\r
- TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),\r
- If->TransferSyntax.SyntaxVersion.MajorVersion,\r
- If->TransferSyntax.SyntaxVersion.MinorVersion);\r
- TRACE(" dispatch table: %p\n", If->DispatchTable);\r
- if (If->DispatchTable) {\r
- TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);\r
- for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {\r
- TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);\r
- }\r
- TRACE(" reserved: %ld\n", If->DispatchTable->Reserved);\r
- }\r
- TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);\r
- TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);\r
- TRACE(" interpreter info: %p\n", If->InterpreterInfo);\r
-\r
- sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));\r
- sif->If = If;\r
- if (MgrTypeUuid) {\r
- memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));\r
- sif->MgrEpv = MgrEpv;\r
- } else {\r
- memset(&sif->MgrTypeUuid, 0, sizeof(UUID));\r
- sif->MgrEpv = If->DefaultManagerEpv;\r
- }\r
- sif->Flags = Flags;\r
- sif->MaxCalls = MaxCalls;\r
- sif->MaxRpcSize = MaxRpcSize;\r
- sif->IfCallbackFn = IfCallbackFn;\r
-\r
- EnterCriticalSection(&server_cs);\r
- sif->Next = ifs;\r
- ifs = sif;\r
- LeaveCriticalSection(&server_cs);\r
-\r
- if (sif->Flags & RPC_IF_AUTOLISTEN) {\r
- /* well, start listening, I think... */\r
- RPCRT4_start_listen();\r
- }\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUnregisterIf (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )\r
-{\r
- FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n",\r
- IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerUnregisterIfEx (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )\r
-{\r
- FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",\r
- IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcObjectSetType (RPCRT4.@)\r
- *\r
- * PARAMS\r
- * ObjUuid [I] "Object" UUID\r
- * TypeUuid [I] "Type" UUID\r
- *\r
- * RETURNS\r
- * RPC_S_OK The call succeeded\r
- * RPC_S_INVALID_OBJECT The provided object (nil) is not valid\r
- * RPC_S_ALREADY_REGISTERED The provided object is already registered\r
- *\r
- * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type\r
- * resets the mapping for the specified object UUID to nil (the default).\r
- * The nil object is always associated with the nil type and cannot be\r
- * reassigned. Servers can support multiple implementations on the same\r
- * interface by registering different end-point vectors for the different\r
- * types. There's no need to call this if a server only supports the nil\r
- * type, as is typical.\r
- */\r
-RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )\r
-{\r
- RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;\r
- RPC_STATUS dummy;\r
-\r
- TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));\r
- if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {\r
- /* nil uuid cannot be remapped */\r
- return RPC_S_INVALID_OBJECT;\r
- }\r
-\r
- /* find the mapping for this object if there is one ... */\r
- while (map) {\r
- if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;\r
- prev = map;\r
- map = map->next;\r
- }\r
- if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {\r
- /* ... and drop it from the list */\r
- if (map) {\r
- if (prev) \r
- prev->next = map->next;\r
- else\r
- RpcObjTypeMaps = map->next;\r
- HeapFree(GetProcessHeap(), 0, map);\r
- }\r
- } else {\r
- /* ... , fail if we found it ... */\r
- if (map)\r
- return RPC_S_ALREADY_REGISTERED;\r
- /* ... otherwise create a new one and add it in. */\r
- map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));\r
- memcpy(&map->Object, ObjUuid, sizeof(UUID));\r
- memcpy(&map->Type, TypeUuid, sizeof(UUID));\r
- map->next = NULL;\r
- if (prev)\r
- prev->next = map; /* prev is the last map in the linklist */\r
- else\r
- RpcObjTypeMaps = map;\r
- }\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerRegisterAuthInfoA (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,\r
- LPVOID Arg )\r
-{\r
- FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );\r
- \r
- return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerRegisterAuthInfoW (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,\r
- LPVOID Arg )\r
-{\r
- FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );\r
- \r
- return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */\r
-}\r
-\r
-/***********************************************************************\r
- * RpcServerListen (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )\r
-{\r
- TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);\r
-\r
- if (!protseqs)\r
- return RPC_S_NO_PROTSEQS_REGISTERED;\r
-\r
- EnterCriticalSection(&listen_cs);\r
-\r
- if (std_listen) {\r
- LeaveCriticalSection(&listen_cs);\r
- return RPC_S_ALREADY_LISTENING;\r
- }\r
-\r
- RPCRT4_start_listen();\r
-\r
- LeaveCriticalSection(&listen_cs);\r
-\r
- if (DontWait) return RPC_S_OK;\r
-\r
- return RpcMgmtWaitServerListen();\r
-}\r
-\r
-/***********************************************************************\r
- * RpcMgmtServerWaitListen (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )\r
-{\r
- RPC_STATUS rslt = RPC_S_OK;\r
-\r
- TRACE("\n");\r
-\r
- EnterCriticalSection(&listen_cs);\r
-\r
- if (!std_listen)\r
- if ( (rslt = RpcServerListen(1, 0, TRUE)) != RPC_S_OK ) {\r
- LeaveCriticalSection(&listen_cs);\r
- return rslt;\r
- }\r
- \r
- LeaveCriticalSection(&listen_cs);\r
-\r
- while (std_listen) {\r
- WaitForSingleObject(mgr_event, INFINITE);\r
- if (!std_listen) {\r
- Sleep(100); /* don't spin violently */\r
- TRACE("spinning.\n");\r
- }\r
- }\r
-\r
- return rslt;\r
-}\r
-\r
-/***********************************************************************\r
- * RpcMgmtStopServerListening (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )\r
-{\r
- TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);\r
-\r
- if (Binding) {\r
- FIXME("client-side invocation not implemented.\n");\r
- return RPC_S_WRONG_KIND_OF_BINDING;\r
- }\r
- \r
- /* hmm... */\r
- EnterCriticalSection(&listen_cs);\r
- while (std_listen)\r
- RPCRT4_stop_listen();\r
- LeaveCriticalSection(&listen_cs);\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcServerStartListening (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )\r
-{\r
- FIXME( "(%p): stub\n", hWnd );\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcServerStopListening (RPCRT4.@)\r
- */\r
-RPC_STATUS WINAPI I_RpcServerStopListening( void )\r
-{\r
- FIXME( "(): stub\n" );\r
-\r
- return RPC_S_OK;\r
-}\r
-\r
-/***********************************************************************\r
- * I_RpcWindowProc (RPCRT4.@)\r
- */\r
-UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )\r
-{\r
- FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );\r
-\r
- return 0;\r
-}\r
+/*
+ * RPC server API
+ *
+ * Copyright 2001 Ove Kåven, TransGaming Technologies
+ * Copyright 2004 Filip Navara
+ *
+ * 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:
+ * - a whole lot
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "ntstatus.h"
+
+#include "rpc.h"
+#include "rpcndr.h"
+#include "excpt.h"
+
+#include "wine/debug.h"
+#include "wine/exception.h"
+
+#include "rpc_server.h"
+#include "rpc_misc.h"
+#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;
+} RpcPacket;
+
+typedef struct _RpcObjTypeMap
+{
+ /* FIXME: a hash table would be better. */
+ struct _RpcObjTypeMap *next;
+ UUID Object;
+ UUID Type;
+} RpcObjTypeMap;
+
+static RpcObjTypeMap *RpcObjTypeMaps;
+
+static RpcServerProtseq* protseqs;
+static RpcServerInterface* ifs;
+
+static CRITICAL_SECTION server_cs;
+static CRITICAL_SECTION_DEBUG server_cs_debug =
+{
+ 0, 0, &server_cs,
+ { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
+ 0, 0, { 0, (DWORD)(__FILE__ ": server_cs") }
+};
+static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
+
+static CRITICAL_SECTION listen_cs;
+static CRITICAL_SECTION_DEBUG listen_cs_debug =
+{
+ 0, 0, &listen_cs,
+ { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
+ 0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") }
+};
+static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
+
+/* whether the server is currently listening */
+static BOOL std_listen;
+/* number of manual listeners (calls to RpcServerListen) */
+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, { 0, (DWORD)(__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)
+{
+ RpcObjTypeMap *rslt = RpcObjTypeMaps;
+ RPC_STATUS dummy;
+
+ while (rslt) {
+ if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
+ rslt = rslt->next;
+ }
+
+ return rslt;
+}
+
+inline static UUID *LookupObjType(UUID *ObjUuid)
+{
+ RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
+ if (map)
+ return &map->Type;
+ else
+ return &uuid_nil;
+}
+
+static RpcServerInterface* RPCRT4_find_interface(UUID* object,
+ RPC_SYNTAX_IDENTIFIER* if_id,
+ BOOL check_object)
+{
+ UUID* MgrType = NULL;
+ RpcServerInterface* cif = NULL;
+ RPC_STATUS status;
+
+ if (check_object)
+ MgrType = LookupObjType(object);
+ EnterCriticalSection(&server_cs);
+ cif = ifs;
+ while (cif) {
+ 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;
+ }
+ LeaveCriticalSection(&server_cs);
+ TRACE("returning %p for %s\n", cif, debugstr_guid(object));
+ return cif;
+}
+
+static void RPCRT4_push_packet(RpcPacket* packet)
+{
+ packet->next = NULL;
+ EnterCriticalSection(&spacket_cs);
+ if (spacket_tail) {
+ spacket_tail->next = packet;
+ spacket_tail = packet;
+ } else {
+ spacket_head = packet;
+ spacket_tail = packet;
+ }
+ 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);
+ TRACE("returning failure packet\n");
+ 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");
+
+ /* FIXME: do more checks! */
+ if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE ||
+ !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
+ TRACE("packet size less than min size, or active interface syntax guid non-null\n");
+ sif = NULL;
+ } else {
+ sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE);
+ }
+ if (sif == NULL) {
+ TRACE("rejecting bind request on connection %p\n", conn);
+ /* Report failure to client. */
+ response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
+ RPC_VER_MAJOR, RPC_VER_MINOR);
+ } else {
+ TRACE("accepting bind request on connection %p\n", conn);
+
+ /* accept. */
+ response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
+ RPC_MAX_PACKET_SIZE,
+ RPC_MAX_PACKET_SIZE,
+ conn->Endpoint,
+ RESULT_ACCEPT, NO_REASON,
+ &sif->If->TransferSyntax);
+
+ /* save the interface for later use */
+ conn->ActiveInterface = hdr->bind.abstract;
+ conn->MaxTransmissionSize = hdr->bind.max_tsize;
+ }
+
+ if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK)
+ goto fail;
+
+ break;
+
+ case PKT_REQUEST:
+ TRACE("got request packet\n");
+
+ /* fail if the connection isn't bound with an interface */
+ if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
+ response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
+ status);
+
+ RPCRT4_Send(conn, response, NULL, 0);
+ break;
+ }
+
+ if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
+ object_uuid = (UUID*)(&hdr->request + 1);
+ } else {
+ object_uuid = NULL;
+ }
+
+ sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE);
+ msg->RpcInterfaceInformation = sif->If;
+ /* copy the endpoint vector from sif to msg so that midl-generated code will use it */
+ msg->ManagerEpv = sif->MgrEpv;
+ if (object_uuid != NULL) {
+ RPCRT4_SetBindingObject(msg->Handle, object_uuid);
+ }
+
+ /* find dispatch function */
+ msg->ProcNum = hdr->request.opnum;
+ if (sif->Flags & RPC_IF_OLE) {
+ /* native ole32 always gives us a dispatch table with a single entry
+ * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
+ func = *sif->If->DispatchTable->DispatchTable;
+ } else {
+ if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
+ ERR("invalid procnum\n");
+ func = NULL;
+ }
+ func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];
+ }
+
+ /* put in the drep. FIXME: is this more universally applicable?
+ perhaps we should move this outward... */
+ msg->DataRepresentation =
+ MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),
+ 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 */
+ } __ENDTRY
+#else
+ if (func) func(msg);
+#endif
+
+ /* send response packet */
+ I_RpcSend(msg);
+
+ msg->RpcInterfaceInformation = NULL;
+
+ break;
+
+ default:
+ FIXME("unhandled packet type\n");
+ break;
+ }
+
+fail:
+ /* clean up */
+ if (msg->Buffer == buf) msg->Buffer = NULL;
+ TRACE("freeing Buffer=%p\n", buf);
+ HeapFree(GetProcessHeap(), 0, buf);
+ RPCRT4_DestroyBinding(msg->Handle);
+ msg->Handle = 0;
+ I_RpcFreeBuffer(msg);
+ msg->Buffer = NULL;
+ RPCRT4_FreeHeader(hdr);
+#ifndef __REACTOS__
+ TlsSetValue(worker_tls, NULL);
+#endif
+}
+
+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);
+ 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;
+ RpcPktHdr *hdr;
+ RpcBinding *pbind;
+ RPC_MESSAGE *msg;
+ RPC_STATUS status;
+ RpcPacket *packet;
+
+ TRACE("(%p)\n", conn);
+
+ for (;;) {
+ msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
+
+ /* create temporary binding for dispatch, it will be freed in
+ * RPCRT4_process_packet */
+ RPCRT4_MakeBinding(&pbind, conn);
+ msg->Handle = (RPC_BINDING_HANDLE)pbind;
+
+ status = RPCRT4_Receive(conn, &hdr, msg);
+ if (status != RPC_S_OK) {
+ WARN("receive failed with error %lx\n", status);
+ break;
+ }
+
+#if 0
+ RPCRT4_process_packet(conn, hdr, msg);
+#else
+ packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
+ packet->conn = conn;
+ packet->hdr = hdr;
+ packet->msg = msg;
+ RPCRT4_create_worker_if_needed();
+ RPCRT4_push_packet(packet);
+ ReleaseSemaphore(server_sem, 1, NULL);
+#endif
+ msg = NULL;
+ }
+ HeapFree(GetProcessHeap(), 0, msg);
+ RPCRT4_DestroyConnection(conn);
+ return 0;
+}
+
+static 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);
+ RPCRT4_DestroyConnection(conn);
+ }
+ /* we could set conn->thread, but then we'd have to make the io_thread wait
+ * for that, otherwise the thread might finish, destroy the connection, and
+ * free the memory we'd write to before we did, causing crashes and stuff -
+ * so let's implement that later, when we really need conn->thread */
+
+ CloseHandle( thread );
+}
+
+static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
+{
+ HANDLE m_event = mgr_event, b_handle;
+ HANDLE *objs = NULL;
+ DWORD count, res;
+ RpcServerProtseq* cps;
+ 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);
+
+ if (set_ready_event)
+ {
+ /* signal to function that changed state that we are now sync'ed */
+ SetEvent(server_ready_event);
+ set_ready_event = FALSE;
+ }
+
+ /* start waiting */
+ res = WaitForMultipleObjects(count, objs, FALSE, INFINITE);
+ if (res == WAIT_OBJECT_0) {
+ if (!std_listen)
+ {
+ SetEvent(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);
+ /* close connections */
+ cps = protseqs;
+ while (cps) {
+ conn = cps->conn;
+ while (conn) {
+ RPCRT4_CloseConnection(conn);
+ conn = conn->Next;
+ }
+ cps = cps->Next;
+ }
+ LeaveCriticalSection(&server_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)
+{
+ /* 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);
+
+ SetEvent(mgr_event);
+ /* wait for server thread to make the requested changes before returning */
+ WaitForSingleObject(server_ready_event, INFINITE);
+
+ ReleaseMutex(mgr_mutex);
+}
+
+static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
+{
+ RPC_STATUS status = RPC_S_ALREADY_LISTENING;
+
+ TRACE("\n");
+
+ EnterCriticalSection(&listen_cs);
+ 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();
+ std_listen = TRUE;
+ server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL);
+ CloseHandle(server_thread);
+ }
+ }
+ LeaveCriticalSection(&listen_cs);
+
+ return status;
+}
+
+static void RPCRT4_stop_listen(BOOL auto_listen)
+{
+ EnterCriticalSection(&listen_cs);
+ if (auto_listen || (--manual_listen_count == 0))
+ {
+ if (listen_count != 0 && --listen_count == 0) {
+ std_listen = FALSE;
+ LeaveCriticalSection(&listen_cs);
+ RPCRT4_sync_with_server_thread();
+ return;
+ }
+ assert(listen_count >= 0);
+ }
+ LeaveCriticalSection(&listen_cs);
+}
+
+static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps)
+{
+ RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL);
+
+ EnterCriticalSection(&server_cs);
+ ps->Next = protseqs;
+ protseqs = ps;
+ LeaveCriticalSection(&server_cs);
+
+ if (std_listen) RPCRT4_sync_with_server_thread();
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RpcServerInqBindings (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
+{
+ RPC_STATUS status;
+ DWORD count;
+ RpcServerProtseq* ps;
+ RpcConnection* conn;
+
+ if (BindingVector)
+ TRACE("(*BindingVector == ^%p)\n", *BindingVector);
+ else
+ ERR("(BindingVector == NULL!!?)\n");
+
+ EnterCriticalSection(&server_cs);
+ /* count connections */
+ count = 0;
+ ps = protseqs;
+ while (ps) {
+ conn = ps->conn;
+ while (conn) {
+ count++;
+ conn = conn->Next;
+ }
+ ps = ps->Next;
+ }
+ if (count) {
+ /* export bindings */
+ *BindingVector = HeapAlloc(GetProcessHeap(), 0,
+ sizeof(RPC_BINDING_VECTOR) +
+ sizeof(RPC_BINDING_HANDLE)*(count-1));
+ (*BindingVector)->Count = count;
+ count = 0;
+ ps = protseqs;
+ while (ps) {
+ conn = ps->conn;
+ while (conn) {
+ RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
+ conn);
+ count++;
+ conn = conn->Next;
+ }
+ ps = ps->Next;
+ }
+ status = RPC_S_OK;
+ } else {
+ *BindingVector = NULL;
+ status = RPC_S_NO_BINDINGS;
+ }
+ LeaveCriticalSection(&server_cs);
+ return status;
+}
+
+/***********************************************************************
+ * RpcServerUseProtseqEpA (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor )
+{
+ RPC_POLICY policy;
+
+ TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
+
+ /* This should provide the default behaviour */
+ policy.Length = sizeof( policy );
+ policy.EndpointFlags = 0;
+ policy.NICFlags = 0;
+
+ return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
+}
+
+/***********************************************************************
+ * RpcServerUseProtseqEpW (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor )
+{
+ RPC_POLICY policy;
+
+ TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
+
+ /* This should provide the default behaviour */
+ policy.Length = sizeof( policy );
+ policy.EndpointFlags = 0;
+ policy.NICFlags = 0;
+
+ return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
+}
+
+/***********************************************************************
+ * RpcServerUseProtseqEpExA (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor,
+ PRPC_POLICY lpPolicy )
+{
+ RpcServerProtseq* ps;
+
+ TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( (char*)Protseq ), MaxCalls,
+ debugstr_a( (char*)Endpoint ), 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);
+
+ return RPCRT4_use_protseq(ps);
+}
+
+/***********************************************************************
+ * RpcServerUseProtseqEpExW (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor,
+ PRPC_POLICY lpPolicy )
+{
+ RpcServerProtseq* ps;
+
+ 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);
+
+ return RPCRT4_use_protseq(ps);
+}
+
+/***********************************************************************
+ * RpcServerUseProtseqA (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *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);
+}
+
+/***********************************************************************
+ * RpcServerUseProtseqW (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR 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);
+}
+
+/***********************************************************************
+ * RpcServerRegisterIf (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
+{
+ TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
+ return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
+}
+
+/***********************************************************************
+ * RpcServerRegisterIfEx (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
+ UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
+{
+ TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
+ return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
+}
+
+/***********************************************************************
+ * RpcServerRegisterIf2 (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
+ UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
+{
+ PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
+ RpcServerInterface* sif;
+ unsigned int i;
+
+ TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
+ MaxRpcSize, IfCallbackFn);
+ TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
+ If->InterfaceId.SyntaxVersion.MajorVersion,
+ If->InterfaceId.SyntaxVersion.MinorVersion);
+ TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
+ If->TransferSyntax.SyntaxVersion.MajorVersion,
+ If->TransferSyntax.SyntaxVersion.MinorVersion);
+ TRACE(" dispatch table: %p\n", If->DispatchTable);
+ if (If->DispatchTable) {
+ TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
+ for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
+ TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
+ }
+ TRACE(" reserved: %ld\n", If->DispatchTable->Reserved);
+ }
+ TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
+ TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
+ TRACE(" interpreter info: %p\n", If->InterpreterInfo);
+
+ sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
+ sif->If = If;
+ if (MgrTypeUuid) {
+ memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID));
+ sif->MgrEpv = MgrEpv;
+ } else {
+ memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
+ sif->MgrEpv = If->DefaultManagerEpv;
+ }
+ sif->Flags = Flags;
+ sif->MaxCalls = MaxCalls;
+ sif->MaxRpcSize = MaxRpcSize;
+ sif->IfCallbackFn = IfCallbackFn;
+
+ EnterCriticalSection(&server_cs);
+ sif->Next = ifs;
+ ifs = sif;
+ 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();
+ }
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RpcServerUnregisterIf (RPCRT4.@)
+ */
+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);
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RpcServerUnregisterIfEx (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
+{
+ FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
+ IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RpcObjectSetType (RPCRT4.@)
+ *
+ * PARAMS
+ * ObjUuid [I] "Object" UUID
+ * TypeUuid [I] "Type" UUID
+ *
+ * RETURNS
+ * RPC_S_OK The call succeeded
+ * RPC_S_INVALID_OBJECT The provided object (nil) is not valid
+ * RPC_S_ALREADY_REGISTERED The provided object is already registered
+ *
+ * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type
+ * resets the mapping for the specified object UUID to nil (the default).
+ * The nil object is always associated with the nil type and cannot be
+ * reassigned. Servers can support multiple implementations on the same
+ * interface by registering different end-point vectors for the different
+ * types. There's no need to call this if a server only supports the nil
+ * type, as is typical.
+ */
+RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
+{
+ RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
+ RPC_STATUS dummy;
+
+ TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
+ if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
+ /* nil uuid cannot be remapped */
+ return RPC_S_INVALID_OBJECT;
+ }
+
+ /* find the mapping for this object if there is one ... */
+ while (map) {
+ if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
+ prev = map;
+ map = map->next;
+ }
+ if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
+ /* ... and drop it from the list */
+ if (map) {
+ if (prev)
+ prev->next = map->next;
+ else
+ RpcObjTypeMaps = map->next;
+ HeapFree(GetProcessHeap(), 0, map);
+ }
+ } else {
+ /* ... , fail if we found it ... */
+ if (map)
+ return RPC_S_ALREADY_REGISTERED;
+ /* ... otherwise create a new one and add it in. */
+ map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
+ memcpy(&map->Object, ObjUuid, sizeof(UUID));
+ memcpy(&map->Type, TypeUuid, sizeof(UUID));
+ map->next = NULL;
+ if (prev)
+ prev->next = map; /* prev is the last map in the linklist */
+ else
+ RpcObjTypeMaps = map;
+ }
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RpcServerRegisterAuthInfoA (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
+ LPVOID Arg )
+{
+ FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg );
+
+ return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
+}
+
+/***********************************************************************
+ * RpcServerRegisterAuthInfoW (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
+ LPVOID Arg )
+{
+ FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg );
+
+ return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */
+}
+
+/***********************************************************************
+ * RpcServerListen (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
+{
+ RPC_STATUS status;
+
+ TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
+
+ if (!protseqs)
+ return RPC_S_NO_PROTSEQS_REGISTERED;
+
+ status = RPCRT4_start_listen(FALSE);
+
+ if (DontWait || (status != RPC_S_OK)) return status;
+
+ return RpcMgmtWaitServerListen();
+}
+
+/***********************************************************************
+ * RpcMgmtServerWaitListen (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
+{
+ TRACE("()\n");
+
+ EnterCriticalSection(&listen_cs);
+
+ if (!std_listen) {
+ LeaveCriticalSection(&listen_cs);
+ return RPC_S_NOT_LISTENING;
+ }
+
+ LeaveCriticalSection(&listen_cs);
+
+ RPCRT4_sync_with_server_thread();
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * RpcMgmtStopServerListening (RPCRT4.@)
+ */
+RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
+{
+ TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
+
+ if (Binding) {
+ FIXME("client-side invocation not implemented.\n");
+ return RPC_S_WRONG_KIND_OF_BINDING;
+ }
+
+ RPCRT4_stop_listen(FALSE);
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * I_RpcServerStartListening (RPCRT4.@)
+ */
+RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )
+{
+ FIXME( "(%p): stub\n", hWnd );
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * I_RpcServerStopListening (RPCRT4.@)
+ */
+RPC_STATUS WINAPI I_RpcServerStopListening( void )
+{
+ FIXME( "(): stub\n" );
+
+ return RPC_S_OK;
+}
+
+/***********************************************************************
+ * I_RpcWindowProc (RPCRT4.@)
+ */
+UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
+{
+ FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam );
+
+ return 0;
+}