Sync to Wine-20050830:
[reactos.git] / reactos / lib / rpcrt4 / rpc_server.c
index bb3cb95..c748ac4 100644 (file)
-/*\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;
+}