From 9e1c7a30c72f0c3a76926561a5254fb29e111fa4 Mon Sep 17 00:00:00 2001
From: Rob Shearman <robertshearman@gmail.com>
Date: Wed, 25 Jun 2008 18:26:56 +0100
Subject: [PATCH] rpcrt4: Use DCE/RPC to contact the endpoint-mapper server.

---
 .gitignore               |   2 +
 dlls/rpcrt4/Makefile.in  |   3 +
 dlls/rpcrt4/epm.idl      |  19 ++
 dlls/rpcrt4/epm_towers.h |   6 +-
 dlls/rpcrt4/rpc_epmap.c  | 453 ++++++++++++++++++++++++++++-----------
 5 files changed, 353 insertions(+), 130 deletions(-)
 create mode 100644 dlls/rpcrt4/epm.idl

diff --git a/.gitignore b/.gitignore
index 4d8443a2402..75698d9ef98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -346,6 +346,8 @@ dlls/riched20/tests/testlist.c
 dlls/riched32/tests/*.ok
 dlls/riched32/tests/riched32_crosstest.exe
 dlls/riched32/tests/testlist.c
+dlls/rpcrt4/epm.h
+dlls/rpcrt4/epm_c.c
 dlls/rpcrt4/librpcrt4.def
 dlls/rpcrt4/tests/*.ok
 dlls/rpcrt4/tests/rpcrt4_crosstest.exe
diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in
index fed47461e18..5293b71f7ee 100644
--- a/dlls/rpcrt4/Makefile.in
+++ b/dlls/rpcrt4/Makefile.in
@@ -30,6 +30,9 @@ C_SRCS = \
 
 RC_SRCS = version.rc
 
+IDL_C_SRCS = \
+	epm.idl
+
 @MAKE_DLL_RULES@
 
 @DEPENDENCIES@  # everything below this line is overwritten by make depend
diff --git a/dlls/rpcrt4/epm.idl b/dlls/rpcrt4/epm.idl
new file mode 100644
index 00000000000..67fad348c88
--- /dev/null
+++ b/dlls/rpcrt4/epm.idl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2008 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/epm.idl"
diff --git a/dlls/rpcrt4/epm_towers.h b/dlls/rpcrt4/epm_towers.h
index 7570cc2e846..f38d4872872 100644
--- a/dlls/rpcrt4/epm_towers.h
+++ b/dlls/rpcrt4/epm_towers.h
@@ -19,6 +19,8 @@
  *
  */
 
+#include "wine/epm.h"
+
 #define EPM_PROTOCOL_DNET_NSP		0x04
 #define EPM_PROTOCOL_OSI_TP4  		0x05
 #define EPM_PROTOCOL_OSI_CLNS 		0x06
@@ -48,10 +50,6 @@
 
 #include <pshpack1.h>
 
-typedef unsigned char u_int8;
-typedef unsigned short u_int16;
-typedef unsigned int u_int32;
-
 typedef struct
 {
     u_int16 count_lhs;
diff --git a/dlls/rpcrt4/rpc_epmap.c b/dlls/rpcrt4/rpc_epmap.c
index 46244ec36e0..074217e72c9 100644
--- a/dlls/rpcrt4/rpc_epmap.c
+++ b/dlls/rpcrt4/rpc_epmap.c
@@ -3,6 +3,7 @@
  *
  * Copyright 2002 Greg Turner
  * Copyright 2001 Ove Kåven, TransGaming Technologies
+ * Copyright 2008 Robert Shearman (for CodeWeavers)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -17,14 +18,9 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * TODO:
- *  - actually do things right
  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -33,8 +29,10 @@
 #include "rpc.h"
 
 #include "wine/debug.h"
+#include "wine/exception.h"
 
 #include "rpc_binding.h"
+#include "epm.h"
 #include "epm_towers.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
@@ -43,8 +41,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
  *
  *  ncadg_ip_udp: 135
  *  ncacn_ip_tcp: 135
- *  ncacn_np: \\pipe\epmapper (?)
+ *  ncacn_np: \\pipe\epmapper
  *  ncalrpc: epmapper
+ *  ncacn_http: 593
  *
  * If the user's machine ran a DCE RPC daemon, it would
  * probably be possible to connect to it, but there are many
@@ -63,77 +62,210 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
  * of running a fully functional DCOM server using Wine...
  */
 
+static const struct epm_endpoints
+{
+    const char *protseq;
+    const char *endpoint;
+} epm_endpoints[] =
+{
+    { "ncacn_np", "\\pipe\\epmapper" },
+    { "ncacn_ip_tcp", "135" },
+    { "ncacn_ip_udp", "135" },
+    { "ncalprc", "epmapper" },
+    { "ncacn_http", "593" },
+};
+
+static BOOL start_rpcss(void)
+{
+    PROCESS_INFORMATION pi;
+    STARTUPINFOW si;
+    static WCHAR cmd[6];
+    static const WCHAR rpcss[] = {'r','p','c','s','s',0};
+    BOOL rslt;
+
+    TRACE("\n");
+
+    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+    ZeroMemory(&si, sizeof(STARTUPINFOA));
+    si.cb = sizeof(STARTUPINFOA);
+
+    memcpy(cmd, rpcss, sizeof(rpcss));
+
+    rslt = CreateProcessW(
+                          NULL,           /* executable */
+                          cmd,            /* command line */
+                          NULL,           /* process security attributes */
+                          NULL,           /* primary thread security attributes */
+                          FALSE,          /* inherit handles */
+                          0,              /* creation flags */
+                          NULL,           /* use parent's environment */
+                          NULL,           /* use parent's current directory */
+                          &si,            /* STARTUPINFO pointer */
+                          &pi             /* PROCESS_INFORMATION */
+                          );
+
+    if (rslt)
+    {
+        CloseHandle(pi.hProcess);
+        CloseHandle(pi.hThread);
+        Sleep(100);
+    }
+
+    return rslt;
+}
+
+static RPC_STATUS get_epm_handle_client(RPC_BINDING_HANDLE handle, RPC_BINDING_HANDLE *epm_handle)
+{
+    RpcBinding *bind = (RpcBinding *)handle;
+    const char * pszEndpoint = NULL;
+    RPC_STATUS status;
+    RpcBinding* epm_bind;
+    unsigned int i;
+
+    if (bind->server)
+        return RPC_S_INVALID_BINDING;
+
+    for (i = 0; i < sizeof(epm_endpoints)/sizeof(epm_endpoints[0]); i++)
+        if (!strcmp(bind->Protseq, epm_endpoints[i].protseq))
+            pszEndpoint = epm_endpoints[i].endpoint;
+
+    if (!pszEndpoint)
+    {
+        FIXME("no endpoint for the endpoint-mapper found for protseq %s\n", debugstr_a(bind->Protseq));
+        return RPC_S_PROTSEQ_NOT_SUPPORTED;
+    }
+
+    status = RpcBindingCopy(handle, epm_handle);
+    if (status != RPC_S_OK) return status;
+
+    epm_bind = (RpcBinding*)*epm_handle;
+    if (epm_bind->AuthInfo)
+    {
+        /* don't bother with authenticating against the EPM by default
+        * (see EnableAuthEpResolution registry value) */
+        RpcAuthInfo_Release(epm_bind->AuthInfo);
+        epm_bind->AuthInfo = NULL;
+    }
+    RPCRT4_ResolveBinding(epm_bind, pszEndpoint);
+    TRACE("RPC_S_OK\n");
+    return RPC_S_OK;
+}
+
+static RPC_STATUS get_epm_handle_server(RPC_BINDING_HANDLE *epm_handle)
+{
+    unsigned char string_binding[] = "ncacn_np:.[\\pipe\\epmapper]";
+
+    return RpcBindingFromStringBindingA(string_binding, epm_handle);
+}
+
+static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *__eptr)
+{
+    switch (GetExceptionCode())
+    {
+        case EXCEPTION_ACCESS_VIOLATION:
+        case EXCEPTION_ILLEGAL_INSTRUCTION:
+            return EXCEPTION_CONTINUE_SEARCH;
+        default:
+            return EXCEPTION_EXECUTE_HANDLER;
+    }
+}
+
 /***********************************************************************
  *             RpcEpRegisterA (RPCRT4.@)
  */
 RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
                                   UUID_VECTOR *UuidVector, RPC_CSTR Annotation )
 {
-  RPCSS_NP_MESSAGE msg;
-  RPCSS_NP_REPLY reply;
-  char *vardata_payload, *vp;
   PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
-  unsigned long c;
-  RPC_STATUS rslt = RPC_S_OK;
+  unsigned long i;
+  RPC_STATUS status = RPC_S_OK;
+  error_status_t status2;
+  ept_entry_t *entries;
+  handle_t handle;
 
   TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a((char*)Annotation));
   TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
-  for (c=0; c<BindingVector->Count; c++) {
-    RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]);
-    TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq));
-    TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint));
+  for (i=0; i<BindingVector->Count; i++) {
+    RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]);
+    TRACE(" protseq[%ld]=%s\n", i, debugstr_a(bind->Protseq));
+    TRACE(" endpoint[%ld]=%s\n", i, debugstr_a(bind->Endpoint));
   }
   if (UuidVector) {
-    for (c=0; c<UuidVector->Count; c++)
-      TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c]));
+    for (i=0; i<UuidVector->Count; i++)
+      TRACE(" obj[%ld]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
   }
 
-  /* FIXME: Do something with annotation. */
+  if (!BindingVector->Count) return RPC_S_OK;
 
-  /* construct the message to rpcss */
-  msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG;
-  msg.message.registerepmsg.iface = If->InterfaceId;
-  msg.message.registerepmsg.no_replace = 0;
+  entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1));
+  if (!entries)
+      return RPC_S_OUT_OF_MEMORY;
 
-  msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0;
-  msg.message.registerepmsg.binding_count = BindingVector->Count;
-
-  /* calculate vardata payload size */
-  msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID);
-  for (c=0; c < msg.message.registerepmsg.binding_count; c++) {
-    RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]);
-    msg.vardata_payload_size += strlen(bind->Protseq) + 1;
-    msg.vardata_payload_size += strlen(bind->Endpoint) + 1;
+  status = get_epm_handle_server(&handle);
+  if (status != RPC_S_OK)
+  {
+    HeapFree(GetProcessHeap(), 0, entries);
+    return status;
   }
 
-  /* allocate the payload buffer */
-  vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size);
-  if (!vardata_payload)
-    return RPC_S_OUT_OF_MEMORY;
-
-  /* populate the payload data */
-  for (c=0; c < msg.message.registerepmsg.object_count; c++) {
-    CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID));
-    vp += sizeof(UUID);
+  for (i = 0; i < BindingVector->Count; i++)
+  {
+      unsigned j;
+      RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]);
+      for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
+      {
+          int len = strlen((char *)Annotation);
+          status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax,
+                                  bind->Protseq, bind->Endpoint,
+                                  bind->NetworkAddr,
+                                  &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
+          if (status != RPC_S_OK) break;
+
+          if (UuidVector)
+              memcpy(&entries[i * UuidVector->Count].object, &UuidVector->Uuid[j], sizeof(GUID));
+          else
+              memset(&entries[i].object, 0, sizeof(entries[i].object));
+          memcpy(entries[i].annotation, Annotation, min(len + 1, ept_max_annotation_size));
+      }
   }
 
-  for (c=0; c < msg.message.registerepmsg.binding_count; c++) {
-    RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]);
-    unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1;
-    CopyMemory(vp, bind->Protseq, pslen);
-    vp += pslen;
-    CopyMemory(vp, bind->Endpoint, eplen);
-    vp += eplen;
+  if (status == RPC_S_OK)
+  {
+      while (TRUE)
+      {
+          __TRY
+          {
+              ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
+                         entries, TRUE, &status2);
+          }
+          __EXCEPT(rpc_filter)
+          {
+              status2 = GetExceptionCode();
+          }
+          __ENDTRY
+          if (status2 == RPC_S_SERVER_UNAVAILABLE)
+          {
+              if (start_rpcss())
+                  continue;
+          }
+          if (status2 != RPC_S_OK)
+              ERR("ept_insert failed with error %d\n", status2);
+          status = status2; /* FIXME: convert status? */
+          break;
+      }
   }
+  RpcBindingFree(&handle);
 
-  /* send our request */
-  if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply))
-    rslt = RPC_S_OUT_OF_MEMORY;
+  for (i = 0; i < BindingVector->Count; i++)
+  {
+      unsigned j;
+      for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
+          I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
+  }
 
-  /* free the payload buffer */
-  LocalFree(vardata_payload);
+  HeapFree(GetProcessHeap(), 0, entries);
 
-  return rslt;
+  return status;
 }
 
 /***********************************************************************
@@ -142,68 +274,85 @@ RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bind
 RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector,
                                    UUID_VECTOR *UuidVector )
 {
-  RPCSS_NP_MESSAGE msg;
-  RPCSS_NP_REPLY reply;
-  char *vardata_payload, *vp;
   PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec;
-  unsigned long c;
-  RPC_STATUS rslt = RPC_S_OK;
+  unsigned long i;
+  RPC_STATUS status = RPC_S_OK;
+  error_status_t status2;
+  ept_entry_t *entries;
+  handle_t handle;
 
   TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector);
   TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
-  for (c=0; c<BindingVector->Count; c++) {
-    RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]);
-    TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq));
-    TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint));
+  for (i=0; i<BindingVector->Count; i++) {
+    RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]);
+    TRACE(" protseq[%ld]=%s\n", i, debugstr_a(bind->Protseq));
+    TRACE(" endpoint[%ld]=%s\n", i, debugstr_a(bind->Endpoint));
   }
   if (UuidVector) {
-    for (c=0; c<UuidVector->Count; c++)
-      TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c]));
+    for (i=0; i<UuidVector->Count; i++)
+      TRACE(" obj[%ld]=%s\n", i, debugstr_guid(UuidVector->Uuid[i]));
   }
 
-  /* construct the message to rpcss */
-  msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG;
-  msg.message.unregisterepmsg.iface = If->InterfaceId;
-
-  msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0;
-  msg.message.unregisterepmsg.binding_count = BindingVector->Count;
+  entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*entries) * BindingVector->Count * (UuidVector ? UuidVector->Count : 1));
+  if (!entries)
+      return RPC_S_OUT_OF_MEMORY;
 
-  /* calculate vardata payload size */
-  msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID);
-  for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) {
-    RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]);
-    msg.vardata_payload_size += strlen(bind->Protseq) + 1;
-    msg.vardata_payload_size += strlen(bind->Endpoint) + 1;
+  status = get_epm_handle_server(&handle);
+  if (status != RPC_S_OK)
+  {
+    HeapFree(GetProcessHeap(), 0, entries);
+    return status;
   }
 
-  /* allocate the payload buffer */
-  vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size);
-  if (!vardata_payload)
-    return RPC_S_OUT_OF_MEMORY;
-
-  /* populate the payload data */
-  for (c=0; c < msg.message.unregisterepmsg.object_count; c++) {
-    CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID));
-    vp += sizeof(UUID);
+  for (i = 0; i < BindingVector->Count; i++)
+  {
+      unsigned j;
+      RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[i]);
+      for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
+      {
+          status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax,
+                                  bind->Protseq, bind->Endpoint,
+                                  bind->NetworkAddr,
+                                  &entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
+          if (status != RPC_S_OK) break;
+
+          if (UuidVector)
+              memcpy(&entries[i * UuidVector->Count + j].object, &UuidVector->Uuid[j], sizeof(GUID));
+          else
+              memset(&entries[i].object, 0, sizeof(entries[i].object));
+      }
   }
 
-  for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) {
-    RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]);
-    unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1;
-    CopyMemory(vp, bind->Protseq, pslen);
-    vp += pslen;
-    CopyMemory(vp, bind->Endpoint, eplen);
-    vp += eplen;
+  if (status == RPC_S_OK)
+  {
+      __TRY
+      {
+          ept_insert(handle, BindingVector->Count * (UuidVector ? UuidVector->Count : 1),
+                     entries, TRUE, &status2);
+      }
+      __EXCEPT(rpc_filter)
+      {
+          status2 = GetExceptionCode();
+      }
+      __ENDTRY
+      if (status2 == RPC_S_SERVER_UNAVAILABLE)
+          status2 = EPT_S_NOT_REGISTERED;
+      if (status2 != RPC_S_OK)
+          ERR("ept_insert failed with error %d\n", status2);
+      status = status2; /* FIXME: convert status? */
   }
+  RpcBindingFree(&handle);
 
-  /* send our request */
-  if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply))
-    rslt = RPC_S_OUT_OF_MEMORY;
+  for (i = 0; i < BindingVector->Count; i++)
+  {
+      unsigned j;
+      for (j = 0; j < (UuidVector ? UuidVector->Count : 1); j++)
+          I_RpcFree(entries[i*(UuidVector ? UuidVector->Count : 1) + j].tower);
+  }
 
-  /* free the payload buffer */
-  LocalFree(vardata_payload);
+  HeapFree(GetProcessHeap(), 0, entries);
 
-  return rslt;
+  return status;
 }
 
 /***********************************************************************
@@ -211,51 +360,93 @@ RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *Bin
  */
 RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec )
 {
-  RPCSS_NP_MESSAGE msg;
-  RPCSS_NP_REPLY reply;
   PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec;
   RpcBinding* bind = (RpcBinding*)Binding;
+  RPC_STATUS status;
+  error_status_t status2;
+  handle_t handle;
+  ept_lookup_handle_t entry_handle = NULL;
+  twr_t *tower;
+  twr_t *towers[4] = { NULL };
+  unsigned32 num_towers, i;
+  GUID uuid = GUID_NULL;
+  char *resolved_endpoint = NULL;
 
   TRACE("(%p,%p)\n", Binding, IfSpec);
   TRACE(" protseq=%s\n", debugstr_a(bind->Protseq));
   TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid));
+  TRACE(" networkaddr=%s\n", debugstr_a(bind->NetworkAddr));
   TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID));
 
-  /* FIXME: totally untested */
-
   /* just return for fully bound handles */
   if (bind->Endpoint && (bind->Endpoint[0] != '\0'))
     return RPC_S_OK;
 
-  /* construct the message to rpcss */
-  msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG;
-  msg.message.resolveepmsg.iface = If->InterfaceId;
-  msg.message.resolveepmsg.object = bind->ObjectUuid;
- 
-  msg.vardata_payload_size = strlen(bind->Protseq) + 1;
+  status = get_epm_handle_client(Binding, &handle);
+  if (status != RPC_S_OK) return status;
+  
+  status = TowerConstruct(&If->InterfaceId, &If->TransferSyntax, bind->Protseq,
+                          ((RpcBinding *)handle)->Endpoint,
+                          bind->NetworkAddr, &tower);
+  if (status != RPC_S_OK)
+  {
+      WARN("couldn't get tower\n");
+      RpcBindingFree(&handle);
+      return status;
+  }
 
-  /* send the message */
-  if (!RPCRT4_RPCSSOnDemandCall(&msg, bind->Protseq, &reply))
-    return RPC_S_OUT_OF_MEMORY;
+  while (TRUE)
+  {
+    __TRY
+    {
+      ept_map(handle, &uuid, tower, &entry_handle, sizeof(towers)/sizeof(towers[0]), &num_towers, towers, &status2);
+      /* FIXME: translate status2? */
+    }
+    __EXCEPT(rpc_filter)
+    {
+      status2 = GetExceptionCode();
+    }
+    __ENDTRY
+    if (status2 == RPC_S_SERVER_UNAVAILABLE)
+    {
+      if (start_rpcss())
+        continue;
+    }
+    break;
+  };
 
-  /* empty-string result means not registered */
-  if (reply.as_string[0] == '\0')
-    return EPT_S_NOT_REGISTERED;
-  
-  /* otherwise we fully bind the handle & return RPC_S_OK */
-  return RPCRT4_ResolveBinding(Binding, reply.as_string);
-}
+  RpcBindingFree(&handle);
+  I_RpcFree(tower);
 
-typedef unsigned int unsigned32;
-typedef struct twr_t
+  if (status2 != RPC_S_OK)
+  {
+    ERR("ept_map failed for ifid %s, protseq %s, networkaddr %s\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), bind->Protseq, bind->NetworkAddr);
+    return status2;
+  }
+
+  for (i = 0; i < num_towers; i++)
+  {
+    /* only parse the tower if we haven't already found a suitable
+    * endpoint, otherwise just free the tower */
+    if (!resolved_endpoint)
     {
-    unsigned32 tower_length;
-    /* [size_is] */ BYTE tower_octet_string[ 1 ];
-    } 	twr_t;
+      status = TowerExplode(towers[i], NULL, NULL, NULL, &resolved_endpoint, NULL);
+      TRACE("status = %ld\n", status);
+    }
+    I_RpcFree(towers[i]);
+  }
+
+  if (resolved_endpoint)
+  {
+    RPCRT4_ResolveBinding(Binding, resolved_endpoint);
+    I_RpcFree(resolved_endpoint);
+    return RPC_S_OK;
+  }
+
+  WARN("couldn't find an endpoint\n");
+  return EPT_S_NOT_REGISTERED;
+}
 
-/***********************************************************************
- *             TowerExplode (RPCRT4.@)
- */
 RPC_STATUS WINAPI TowerExplode(
     const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax,
     char **protseq, char **endpoint, char **address)
@@ -388,3 +579,13 @@ RPC_STATUS WINAPI TowerConstruct(
     }
     return RPC_S_OK;
 }
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
+{
+    return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
-- 
GitLab