Damjan Jovanovic : rpcrt4: Added support for RPC TCP servers.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Oct 20 08:00:39 CDT 2006


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

Author: Damjan Jovanovic <damjan.jov at gmail.com>
Date:   Wed Oct 18 18:14:11 2006 +0200

rpcrt4: Added support for RPC TCP servers.

---

 dlls/rpcrt4/rpc_transport.c |  164 ++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/dlls/rpcrt4/rpc_transport.c b/dlls/rpcrt4/rpc_transport.c
index 0f11bfa..f9bd4b4 100644
--- a/dlls/rpcrt4/rpc_transport.c
+++ b/dlls/rpcrt4/rpc_transport.c
@@ -5,6 +5,7 @@
  * Copyright 2003 Mike Hearn
  * Copyright 2004 Filip Navara
  * Copyright 2006 Mike McCormack
+ * Copyright 2006 Damjan Jovanovic
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -48,6 +49,9 @@ #endif
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
 
 #include "windef.h"
 #include "winbase.h"
@@ -448,14 +452,52 @@ typedef struct _RpcConnection_tcp
 {
   RpcConnection common;
   int sock;
+  HANDLE onEventAvailable;
+  HANDLE onEventHandled;
+  BOOL quit;
 } RpcConnection_tcp;
 
+static DWORD WINAPI rpcrt4_tcp_poll_thread(LPVOID arg)
+{
+  RpcConnection_tcp *tcpc;
+  int ret;
+  struct pollfd pollInfo;
+
+  tcpc = (RpcConnection_tcp*) arg;
+  pollInfo.fd = tcpc->sock;
+  pollInfo.events = POLLIN;
+
+  while (!tcpc->quit)
+  {
+    ret = poll(&pollInfo, 1, 1000);
+    if (ret < 0)
+      ERR("poll failed with error %d\n", ret);
+    else
+    {
+      if (pollInfo.revents & POLLIN)
+      {
+        SignalObjectAndWait(tcpc->onEventAvailable,
+          tcpc->onEventHandled, INFINITE, FALSE);
+      }
+    }
+  }
+
+  /* This avoids the tcpc being destroyed before we are done with it */
+  SetEvent(tcpc->onEventAvailable);
+
+  return 0;
+}
+
 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
 {
   RpcConnection_tcp *tcpc;
   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
-  if (tcpc)
-    tcpc->sock = -1;
+  if (tcpc == NULL)
+    return NULL;
+  tcpc->sock = -1;
+  tcpc->onEventAvailable = NULL;
+  tcpc->onEventHandled = NULL;
+  tcpc->quit = FALSE;
   return &tcpc->common;
 }
 
@@ -470,12 +512,6 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_op
 
   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
 
-  if (Connection->server)
-  {
-    ERR("ncacn_ip_tcp servers not supported yet\n");
-    return RPC_S_SERVER_UNAVAILABLE;
-  }
-
   if (tcpc->sock != -1)
     return RPC_S_OK;
 
@@ -514,14 +550,81 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_op
       continue;
     }
 
-    if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
+    if (Connection->server)
     {
-      WARN("connect() failed\n");
-      close(sock);
-      continue;
+      HANDLE thread = NULL;
+      ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
+      if (ret < 0)
+      {
+        WARN("bind failed, error %d\n", ret);
+        goto done;
+      }
+      ret = listen(sock, 10);
+      if (ret < 0)
+      {
+        WARN("listen failed, error %d\n", ret);
+        goto done;
+      }
+      /* need a non-blocking socket, otherwise accept() has a potential
+       * race-condition (poll() says it is readable, connection drops,
+       * and accept() blocks until the next connection comes...)
+       */
+      ret = fcntl(sock, F_SETFL, O_NONBLOCK);
+      if (ret < 0)
+      {
+        WARN("couldn't make socket non-blocking, error %d\n", ret);
+        goto done;
+      }
+      tcpc->onEventAvailable = CreateEventW(NULL, FALSE, FALSE, NULL);
+      if (tcpc->onEventAvailable == NULL)
+      {
+        WARN("creating available event failed, error %lu\n", GetLastError());
+        goto done;
+      }
+      tcpc->onEventHandled = CreateEventW(NULL, FALSE, FALSE, NULL);
+      if (tcpc->onEventHandled == NULL)
+      {
+        WARN("creating handled event failed, error %lu\n", GetLastError());
+        goto done;
+      }
+      tcpc->sock = sock;
+      thread = CreateThread(NULL, 0, rpcrt4_tcp_poll_thread, tcpc, 0, NULL);
+      if (thread == NULL)
+      {
+        WARN("creating server polling thread failed, error %lu\n",
+          GetLastError());
+        tcpc->sock = -1;
+        goto done;
+      }
+      CloseHandle(thread);
+
+    done:
+      if (thread == NULL) /* ie. we failed somewhere */
+      {
+        close(sock);
+        if (tcpc->onEventAvailable != NULL)
+        {
+          CloseHandle(tcpc->onEventAvailable);
+          tcpc->onEventAvailable = NULL;
+        }
+        if (tcpc->onEventHandled != NULL)
+        {
+          CloseHandle(tcpc->onEventHandled);
+          tcpc->onEventHandled = NULL;
+        }
+        continue;
+      }
+    }
+    else /* it's a client */
+    {
+      if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
+      {
+        WARN("connect() failed\n");
+        close(sock);
+        continue;
+      }
+      tcpc->sock = sock;
     }
-
-    tcpc->sock = sock;
 
     freeaddrinfo(ai);
     TRACE("connected\n");
@@ -535,14 +638,29 @@ static RPC_STATUS rpcrt4_ncacn_ip_tcp_op
 
 static HANDLE rpcrt4_conn_tcp_get_wait_handle(RpcConnection *Connection)
 {
-  assert(0);
-  return 0;
+  RpcConnection_tcp *tcpc = (RpcConnection_tcp*) Connection;
+  return tcpc->onEventAvailable;
 }
 
 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
 {
-  assert(0);
-  return RPC_S_SERVER_UNAVAILABLE;
+  int ret;
+  struct sockaddr_in address;
+  socklen_t addrsize;
+  RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
+  RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
+
+  addrsize = sizeof(address);
+  ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
+  SetEvent(server->onEventHandled);
+  if (ret < 0)
+  {
+    ERR("Failed to accept a TCP connection: error %d\n", ret);
+    return RPC_S_SERVER_UNAVAILABLE;
+  }
+  client->sock = ret;
+  TRACE("Accepted a new TCP connection\n");
+  return RPC_S_OK;
 }
 
 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
@@ -568,6 +686,16 @@ static int rpcrt4_conn_tcp_close(RpcConn
   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
 
   TRACE("%d\n", tcpc->sock);
+
+  if (tcpc->onEventAvailable != NULL)
+  {
+    /* it's a server connection */
+    tcpc->quit = TRUE;
+    WaitForSingleObject(tcpc->onEventAvailable, INFINITE);
+    CloseHandle(tcpc->onEventAvailable);
+    CloseHandle(tcpc->onEventHandled);
+  }
+
   if (tcpc->sock != -1)
     close(tcpc->sock);
   tcpc->sock = -1;




More information about the wine-cvs mailing list