[RPCRT4] TCP server support (2/2) accept TCP connections

Damjan Jovanovic damjan.jov at gmail.com
Sun Oct 8 13:20:16 CDT 2006


Adds support for RPC TCP servers using native (as opposed to winsock)
sockets. Probably closes bug 2416.

Is this any better, Robert?

Changelog:
* added support for RPC TCP servers

Damjan Jovanovic
-------------- next part --------------
--- a/AUTHORS	2006-07-10 18:01:06.000000000 +0200
+++ b/AUTHORS	2006-10-08 11:34:59.000000000 +0200
@@ -873,3 +873,4 @@
 Rizsanyi Zsolt
 Per ??ngstr??m
 Peter ??strand
+Damjan Jovanovic
--- a/dlls/rpcrt4/rpc_transport.c	2006-10-01 09:29:06.000000000 +0200
+++ b/dlls/rpcrt4/rpc_transport.c	2006-10-08 11:01:59.000000000 +0200
@@ -441,13 +441,56 @@
 {
   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;
+  fd_set readableSet;
+  struct timeval timeout;
+
+  tcpc = (RpcConnection_tcp*) arg;
+
+  while (!tcpc->quit)
+  {
+    FD_ZERO(&readableSet);
+    FD_SET(tcpc->sock, &readableSet);
+    timeout.tv_sec = 1;
+    timeout.tv_usec = 0;
+    ret = select(tcpc->sock + 1, &readableSet, NULL, NULL, &timeout);
+    if (ret < 0)
+      ERR("select failed with error %d\n", ret);
+    else
+    {
+      if (FD_ISSET(tcpc->sock, &readableSet))
+      {
+        SetEvent(tcpc->onEventAvailable);
+        WaitForSingleObject(tcpc->onEventHandled, INFINITE);
+        ResetEvent(tcpc->onEventHandled);
+      }
+    }
+  }
+
+  /* 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(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
+  if (tcpc == NULL)
+    return NULL;
   tcpc->sock = -1;
+  tcpc->onEventAvailable = NULL;
+  tcpc->onEventHandled = NULL;
+  tcpc->quit = FALSE;
   return &tcpc->common;
 }
 
@@ -462,12 +505,6 @@
 
   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;
 
@@ -506,14 +543,80 @@
       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 (select() says it is readable, connection drops,
+       * and accept() blocks until the next connection comes...)
+       */
+      ret = fcntl(sock, F_GETFL, 0);
+      ret = fcntl(sock, F_SETFL, ret | O_NONBLOCK);
+      if (ret < 0)
+      {
+        WARN("couldn't make socket non-blocking, error %d\n", ret);
+        goto done;
+      }
+      tcpc->onEventAvailable = CreateEventW(NULL, TRUE, FALSE, NULL);
+      if (tcpc->onEventAvailable == NULL)
+      {
+        WARN("creating available event failed, error %lu\n", GetLastError());
+        goto done;
+      }
+      tcpc->onEventHandled = CreateEventW(NULL, TRUE, 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;
+      }
+
+    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");
@@ -527,14 +630,30 @@
 
 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);
+  ResetEvent(server->onEventAvailable);
+  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,
@@ -560,6 +679,16 @@
   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-patches mailing list