[RPCRT4] support for RPC TCP servers

Damjan Jovanovic damjan.jov at gmail.com
Thu Sep 21 09:22:30 CDT 2006


Changelog:
* Makes RPCRT4 use Winsock2 instead of native sockets (needed for
event object support)
* Adds support for TCP (ncacn_ip_tcp protocol) servers

Damjan Jovanovic
-------------- next part --------------
--- a/include/ws2tcpip.h	2006-08-28 20:35:33.000000000 +0200
+++ b/include/ws2tcpip.h	2006-09-16 08:55:45.000000000 +0200
@@ -137,6 +137,8 @@
 #define WS_IFF_MULTICAST      0x00000010 /* multicast is supported */
 #endif /* USE_WS_PREFIX */
 
+#define INET_ADDRSTRLEN	16
+
 #ifndef USE_WS_PREFIX
 #define IP_OPTIONS                      1
 #define IP_HDRINCL                      2
--- a/dlls/rpcrt4/Makefile.in	2006-09-14 21:35:08.000000000 +0200
+++ b/dlls/rpcrt4/Makefile.in	2006-09-15 22:22:17.000000000 +0200
@@ -5,7 +5,7 @@
 VPATH     = @srcdir@
 MODULE    = rpcrt4.dll
 IMPORTLIB = librpcrt4.$(IMPLIBEXT)
-IMPORTS   = iphlpapi advapi32 kernel32 ntdll
+IMPORTS   = iphlpapi advapi32 kernel32 ntdll ws2_32
 DELAYIMPORTS = secur32
 EXTRALIBS = -luuid
 
--- a/dlls/rpcrt4/rpcrt4_main.c	2006-09-14 21:35:08.000000000 +0200
+++ b/dlls/rpcrt4/rpcrt4_main.c	2006-09-17 22:16:10.000000000 +0200
@@ -102,6 +102,7 @@
 #include "winuser.h"
 #include "iptypes.h"
 #include "iphlpapi.h"
+#include "winsock2.h"
 #include "wine/unicode.h"
 #include "rpc.h"
 
@@ -148,9 +149,13 @@
 
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
+    WSADATA wsaData;
+
     switch (fdwReason) {
     case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls(hinstDLL);
+        if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
+          ERR("winsock failed to initialize\n");
         master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME);
         if (!master_mutex)
           ERR("Failed to create master mutex\n");
@@ -159,6 +164,7 @@
     case DLL_PROCESS_DETACH:
         CloseHandle(master_mutex);
         master_mutex = NULL;
+        WSACleanup();
         break;
     }
 
--- a/dlls/rpcrt4/rpc_transport.c	2006-09-14 22:53:55.000000000 +0200
+++ b/dlls/rpcrt4/rpc_transport.c	2006-09-18 19:02:02.000000000 +0200
@@ -30,31 +30,14 @@
 #include <assert.h>
 #include <errno.h>
 
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-# include <arpa/inet.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
 #include "winerror.h"
 #include "winreg.h"
 #include "winternl.h"
+#include "winsock2.h"
+#include "ws2tcpip.h"
 #include "wine/unicode.h"
 
 #include "rpc.h"
@@ -441,13 +424,46 @@
 {
   RpcConnection common;
   int sock;
+  HANDLE event;
 } RpcConnection_tcp;
 
+static const char *gai_strerror(int errcode)
+{
+  switch (errcode)
+  {
+    case EAI_AGAIN: return "Temporary failure in name resolution";
+    case EAI_BADFLAGS: return "Bad value for ai_flags";
+    case EAI_FAIL: return "Non-recoverable failure in name resolution";
+    case EAI_FAMILY: return "ai_family not supported";
+    case EAI_MEMORY: return "Memory allocation failure";
+    case EAI_NONAME: return "Name or service not known";
+    case EAI_SERVICE: return "Servname not supported for ai_socktype";
+    case EAI_SOCKTYPE: return "ai_socktype not supported";
+  }
+  return "Unknown error";
+}
+
+static const char *inet_ntop(int af, const void *src, char *dst, int cnt)
+{
+  if (af == AF_INET)
+  {
+    unsigned int addr = * (unsigned int*) src;
+    if (cnt < INET_ADDRSTRLEN)
+      return NULL;
+    snprintf(dst, cnt, "%u.%u.%u.%u", (addr >> 24) & 0xFF,
+      (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF);
+    return dst;
+  }
+  else
+    return NULL;
+}
+
 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
 {
   RpcConnection_tcp *tcpc;
   tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
   tcpc->sock = -1;
+  tcpc->event = 0;
   return &tcpc->common;
 }
 
@@ -462,12 +478,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,51 +516,115 @@
       continue;
     }
 
-    if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
+    if (Connection->server)
     {
-      WARN("connect() failed\n");
-      close(sock);
-      continue;
+      BOOL success = FALSE;
+      if (bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen) == 0)
+      {
+        if (listen(sock, 5) == 0)
+        {
+          if ((tcpc->event = WSACreateEvent()) != NULL)
+          {
+            if (WSAEventSelect(sock, tcpc->event, FD_ACCEPT) == 0)
+              success = TRUE;
+            else
+              WARN("WSAEventSelect() failed\n");
+          }
+          else
+            WARN("WSACreateEvent() failed\n");
+        }
+        else
+          WARN("listen() failed\n");
+      }
+      else
+        WARN("bind() failed\n");
+
+      if (!success)
+      {
+        closesocket(sock);
+        if (tcpc->event != NULL)
+          WSACloseEvent(tcpc->event);
+        tcpc->event = NULL;
+        continue;
+      }
+    }
+    else
+    {
+      if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
+      {
+        WARN("connect() failed\n");
+        closesocket(sock);
+        continue;
+      }
     }
 
     tcpc->sock = sock;
 
     freeaddrinfo(ai);
-    TRACE("connected\n");
+    TRACE("socket %d %s\n", tcpc->sock,
+      (Connection->server ? "listening" : "connected"));
     return RPC_S_OK;
   }
 
   freeaddrinfo(ai);
-  ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
+  ERR("couldn't open %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
   return RPC_S_SERVER_UNAVAILABLE;
 }
 
 static HANDLE rpcrt4_conn_tcp_get_wait_handle(RpcConnection *Connection)
 {
-  assert(0);
-  return 0;
+  RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
+  return tcpc->event;
 }
 
 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
 {
-  assert(0);
-  return RPC_S_SERVER_UNAVAILABLE;
+  struct sockaddr_in address;
+  int len;
+  u_long zero = 0;
+  RpcConnection_tcp *server = (RpcConnection_tcp *) old_conn;
+  RpcConnection_tcp *client = (RpcConnection_tcp *) new_conn;
+
+  TRACE("Trying to accept new connection...\n");
+  len = sizeof(address);
+  client->sock = accept(server->sock, (struct sockaddr *) &address, &len);
+  WSAResetEvent(server->event);
+  if (client->sock < 0)
+  {
+    WARN("accept failed, error %d\n", WSAGetLastError());
+    return RPC_S_SERVER_UNAVAILABLE;
+  }
+  WSAEventSelect(client->sock, NULL, 0);
+  ioctlsocket(client->sock, FIONBIO, &zero);
+  TRACE("got a new connection, socket %d\n", client->sock);
+  return RPC_S_OK;
 }
 
 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
                                 void *buffer, unsigned int count)
 {
   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
-  int r = recv(tcpc->sock, buffer, count, MSG_WAITALL);
-  TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
-  return r;
+  int rtotal = 0;
+  int r = 0;
+  do
+  {
+    r = recv(tcpc->sock, buffer, count, 0);
+    if (r > 0)
+      rtotal += r;
+    else
+      break;
+  } while (rtotal < count);
+  if (r < 0)
+    rtotal = r;
+  TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, rtotal);
+  return rtotal;
 }
 
 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
                                  const void *buffer, unsigned int count)
 {
   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
-  int r = write(tcpc->sock, buffer, count);
+  int r = send(tcpc->sock, buffer, count, 0);
   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r);
   return r;
 }
@@ -561,8 +635,11 @@
 
   TRACE("%d\n", tcpc->sock);
   if (tcpc->sock != -1)
-    close(tcpc->sock);
+    closesocket(tcpc->sock);
   tcpc->sock = -1;
+  if (tcpc->event != NULL)
+    WSACloseEvent(tcpc->event);
+  tcpc->event = NULL;
   return 0;
 }
 


More information about the wine-patches mailing list