Rob Shearman : rpcrt4: Add a Win32 implementation of ncacn_ip_tcp transport .

Alexandre Julliard julliard at winehq.org
Wed Apr 8 10:05:33 CDT 2009


Module: wine
Branch: master
Commit: 324b4d0243c6fbcd4a8e7cd95d00a610180cb0cb
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=324b4d0243c6fbcd4a8e7cd95d00a610180cb0cb

Author: Rob Shearman <robertshearman at gmail.com>
Date:   Wed Apr  8 12:55:38 2009 +0100

rpcrt4: Add a Win32 implementation of ncacn_ip_tcp transport.

---

 dlls/rpcrt4/rpc_transport.c |  218 ++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 204 insertions(+), 14 deletions(-)

diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 98602d2..390a7d4 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -912,7 +912,12 @@ typedef struct _RpcConnection_tcp
 {
   RpcConnection common;
   int sock;
+#ifdef HAVE_SOCKETPAIR
   int cancel_fds[2];
+#else
+  HANDLE sock_event;
+  HANDLE cancel_event;
+#endif
 } RpcConnection_tcp;
 
 #ifdef HAVE_SOCKETPAIR
@@ -978,30 +983,78 @@ static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
 
 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
 {
-  /* FIXME */
-  return FALSE;
+  static BOOL wsa_inited;
+  if (!wsa_inited)
+  {
+    WSADATA wsadata;
+    WSAStartup(MAKEWORD(2, 2), &wsadata);
+    /* Note: WSAStartup can be called more than once so we don't bother with
+     * making accesses to wsa_inited thread-safe */
+    wsa_inited = TRUE;
+  }
+  tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+  tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+  if (!tcpc->sock_event || !tcpc->cancel_event)
+  {
+    ERR("event creation failed\n");
+    if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
+    return FALSE;
+  }
+  return TRUE;
 }
 
 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
 {
-  /* FIXME */
-  return FALSE;
+  HANDLE wait_handles[2];
+  DWORD res;
+  if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
+  {
+    ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
+    return FALSE;
+  }
+  wait_handles[0] = tcpc->sock_event;
+  wait_handles[1] = tcpc->cancel_event;
+  res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
+  switch (res)
+  {
+  case WAIT_OBJECT_0:
+    return TRUE;
+  case WAIT_OBJECT_0 + 1:
+    return FALSE;
+  default:
+    ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
+    return FALSE;
+  }
 }
 
 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
 {
-  /* FIXME */
-  return FALSE;
+  DWORD res;
+  if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
+  {
+    ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
+    return FALSE;
+  }
+  res = WaitForSingleObject(tcpc->sock_event, INFINITE);
+  switch (res)
+  {
+  case WAIT_OBJECT_0:
+    return TRUE;
+  default:
+    ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
+    return FALSE;
+  }
 }
 
 static void rpcrt4_sock_wait_cancel(RpcConnection_tcp *tcpc)
 {
-  /* FIXME */
+  SetEvent(tcpc->cancel_event);
 }
 
 static void rpcrt4_sock_wait_destroy(RpcConnection_tcp *tcpc)
 {
-  /* FIXME */
+  CloseHandle(tcpc->sock_event);
+  CloseHandle(tcpc->cancel_event);
 }
 
 #endif
@@ -1105,8 +1158,6 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
   return RPC_S_SERVER_UNAVAILABLE;
 }
 
-#ifdef HAVE_SOCKETPAIR
-
 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
 {
     RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
@@ -1266,8 +1317,6 @@ static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *pr
     return status;
 }
 
-#endif
-
 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
 {
   int ret;
@@ -1520,6 +1569,149 @@ static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq
     return 1;
 }
 
+#else /* HAVE_SOCKETPAIR */
+
+typedef struct _RpcServerProtseq_sock
+{
+    RpcServerProtseq common;
+    HANDLE mgr_event;
+} RpcServerProtseq_sock;
+
+static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
+{
+    RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
+    if (ps)
+    {
+        static BOOL wsa_inited;
+        if (!wsa_inited)
+        {
+            WSADATA wsadata;
+            WSAStartup(MAKEWORD(2, 2), &wsadata);
+            /* Note: WSAStartup can be called more than once so we don't bother with
+             * making accesses to wsa_inited thread-safe */
+            wsa_inited = TRUE;
+        }
+        ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+    }
+    return &ps->common;
+}
+
+static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
+{
+    RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
+    SetEvent(sockps->mgr_event);
+}
+
+static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
+{
+    HANDLE *objs = prev_array;
+    RpcConnection_tcp *conn;
+    RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
+
+    EnterCriticalSection(&protseq->cs);
+
+    /* open and count connections */
+    *count = 1;
+    conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
+    while (conn)
+    {
+        if (conn->sock != -1)
+            (*count)++;
+        conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
+    }
+
+    /* make array of connections */
+    if (objs)
+        objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
+    else
+        objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
+    if (!objs)
+    {
+        ERR("couldn't allocate objs\n");
+        LeaveCriticalSection(&protseq->cs);
+        return NULL;
+    }
+
+    objs[0] = sockps->mgr_event;
+    *count = 1;
+    conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
+    while (conn)
+    {
+        if (conn->sock != -1)
+        {
+            int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
+            if (res == SOCKET_ERROR)
+                ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
+            else
+            {
+                objs[*count] = conn->sock_event;
+                (*count)++;
+            }
+        }
+        conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
+    }
+    LeaveCriticalSection(&protseq->cs);
+    return objs;
+}
+
+static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
+{
+    HeapFree(GetProcessHeap(), 0, array);
+}
+
+static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
+{
+    HANDLE b_handle;
+    HANDLE *objs = wait_array;
+    DWORD res;
+    RpcConnection *cconn;
+    RpcConnection_tcp *conn;
+
+    if (!objs)
+        return -1;
+
+    do
+    {
+        /* an alertable wait isn't strictly necessary, but due to our
+         * overlapped I/O implementation in Wine we need to free some memory
+         * by the file user APC being called, even if no completion routine was
+         * specified at the time of starting the async operation */
+        res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
+    } while (res == WAIT_IO_COMPLETION);
+
+    if (res == WAIT_OBJECT_0)
+        return 0;
+    else if (res == WAIT_FAILED)
+    {
+        ERR("wait failed with error %d\n", GetLastError());
+        return -1;
+    }
+    else
+    {
+        b_handle = objs[res - WAIT_OBJECT_0];
+        /* find which connection got a RPC */
+        EnterCriticalSection(&protseq->cs);
+        conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
+        while (conn)
+        {
+            if (b_handle == conn->sock_event) break;
+            conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
+        }
+        cconn = NULL;
+        if (conn)
+            RPCRT4_SpawnConnection(&cconn, &conn->common);
+        else
+            ERR("failed to locate connection for handle %p\n", b_handle);
+        LeaveCriticalSection(&protseq->cs);
+        if (cconn)
+        {
+            RPCRT4_new_client(cconn);
+            return 1;
+        }
+        else return -1;
+    }
+}
+
 #endif  /* HAVE_SOCKETPAIR */
 
 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
@@ -2551,7 +2743,6 @@ static const struct protseq_ops protseq_list[] =
         rpcrt4_protseq_np_wait_for_new_connection,
         rpcrt4_protseq_ncalrpc_open_endpoint,
     },
-#ifdef HAVE_SOCKETPAIR
     {
         "ncacn_ip_tcp",
         rpcrt4_protseq_sock_alloc,
@@ -2561,7 +2752,6 @@ static const struct protseq_ops protseq_list[] =
         rpcrt4_protseq_sock_wait_for_new_connection,
         rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
     },
-#endif
 };
 
 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))




More information about the wine-cvs mailing list