From 2255a1f52d02f6a5e5b137840f6b7f65c80dbb19 Mon Sep 17 00:00:00 2001
From: Erich Hoover <ehoover@mines.edu>
Date: Mon, 13 Dec 2010 18:57:27 -0700
Subject: ntdll: Pass ReadFile and WriteFile requests on sockets to ws2_32.dll.

---
 dlls/ntdll/file.c |  141 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 140 insertions(+), 1 deletions(-)

diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 68bed0e..003fbdd 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -86,6 +86,9 @@
 #include "winioctl.h"
 #include "ddk/ntddser.h"
 
+#define USE_WS_PREFIX
+#include "winsock2.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
 WINE_DECLARE_DEBUG_CHANNEL(winediag);
 
@@ -94,6 +97,85 @@ mode_t FILE_umask = 0;
 #define SECSPERDAY         86400
 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
 
+/* NtStatusToWSAError in dlls/ws2_32/socket.c corresponds to this function */
+static inline NTSTATUS WSAErrorToNtStatus( const int status )
+{
+    /* We only need to cover the status codes set by server async request handling */
+    NTSTATUS nterr;
+    switch ( status )
+    {
+    case 0:                     nterr = STATUS_SUCCESS;                    break;
+    case WSA_IO_PENDING:        nterr = STATUS_PENDING;                    break;
+    case WSAENOTSOCK:           nterr = STATUS_OBJECT_TYPE_MISMATCH;       break;
+    case WSAEBADF:              nterr = STATUS_INVALID_HANDLE;             break;
+    case WSAEINVAL:             nterr = STATUS_INVALID_PARAMETER;          break;
+    case WSAESHUTDOWN:          nterr = STATUS_PIPE_DISCONNECTED;          break;
+    case WSAEALREADY:           nterr = STATUS_NETWORK_BUSY;               break;
+    case WSAENETUNREACH:        nterr = STATUS_NETWORK_UNREACHABLE;        break;
+    case WSAECONNREFUSED:       nterr = STATUS_CONNECTION_REFUSED;         break;
+    case WSAENOTCONN:           nterr = STATUS_CONNECTION_DISCONNECTED;    break;
+    case WSAECONNRESET:         nterr = STATUS_CONNECTION_RESET;           break;
+    case WSAECONNABORTED:       nterr = STATUS_CONNECTION_ABORTED;         break;
+    case WSA_OPERATION_ABORTED: nterr = STATUS_CANCELLED;                  break;
+    case WSAEADDRINUSE:         nterr = STATUS_ADDRESS_ALREADY_ASSOCIATED; break;
+    case WSAETIMEDOUT:          nterr = STATUS_IO_TIMEOUT;                 break;
+    case WSAEFAULT:             nterr = STATUS_NO_MEMORY;                  break;
+    case WSAEACCES:             nterr = STATUS_ACCESS_DENIED;              break;
+    case WSAEMFILE:             nterr = STATUS_TOO_MANY_OPENED_FILES;      break;
+    case WSAEWOULDBLOCK:        nterr = STATUS_CANT_WAIT;                  break;
+    case WSAEMSGSIZE:           nterr = STATUS_BUFFER_OVERFLOW;            break;
+    case WSAEOPNOTSUPP:         nterr = STATUS_NOT_SUPPORTED;              break;
+    case WSAEHOSTUNREACH:       nterr = STATUS_HOST_UNREACHABLE;           break;
+
+    default:
+        if ( status < WSABASEERR || status > WSABASEERR+1004 )
+            FIXME( "Unhandled WSAError code: %d\n", status );
+        else
+            FIXME( "Not a WSAError code: %d\n", status);
+        nterr = STATUS_UNSUCCESSFUL; 
+    }
+    return nterr;
+}
+
+static int (WINAPI *pWSARecv)(SOCKET,LPWSABUF,DWORD,LPDWORD,LPDWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE);
+static int (WINAPI *pWSASend)(SOCKET,LPWSABUF,DWORD,LPDWORD,DWORD,LPWSAOVERLAPPED,LPWSAOVERLAPPED_COMPLETION_ROUTINE);
+static int (WINAPI *pWSAGetLastError)(VOID);
+
+/*
+ * Load the ws2_32 library and allocate the function pointers required
+ * for reading and writing to sockets
+ */
+static inline int LoadWSA(void)
+{
+    WCHAR wsalibW[] = {'w','s','2','_','3','2','.','d','l','l',0 };
+    CHAR cWSAGetLastError[] = "WSAGetLastError";
+    static HMODULE hModule = 0;
+    CHAR cWSARecv[] = "WSARecv";
+    CHAR cWSASend[] = "WSASend";
+    UNICODE_STRING wstr;
+    ANSI_STRING str;
+
+    if (hModule)
+        return TRUE;
+    RtlInitUnicodeString( &wstr, wsalibW );
+    if (LdrLoadDll( NULL, 0, &wstr, &hModule ) != STATUS_SUCCESS)
+        return FALSE;
+    RtlInitAnsiString( &str, (LPCSTR) &cWSAGetLastError );
+    if (LdrGetProcedureAddress( hModule, &str, 0, (void**)&pWSAGetLastError ) != STATUS_SUCCESS)
+        goto failed;
+    RtlInitAnsiString( &str, (LPCSTR) &cWSARecv );
+    if (LdrGetProcedureAddress( hModule, &str, 0, (void**)&pWSARecv ) != STATUS_SUCCESS)
+        goto failed;
+    RtlInitAnsiString( &str, (LPCSTR) &cWSASend );
+    if (LdrGetProcedureAddress( hModule, &str, 0, (void**)&pWSASend ) != STATUS_SUCCESS)
+        goto failed;
+    return TRUE;
+
+failed:
+    LdrUnloadDll( hModule );
+    hModule = 0;
+    return FALSE;
+}
 
 /**************************************************************************
  *                 FILE_CreateFile                    (internal)
@@ -618,6 +700,35 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
         status = total ? STATUS_SUCCESS : STATUS_END_OF_FILE;
         goto done;
     }
+    else if (type == FD_TYPE_SOCKET && LoadWSA())
+    {
+        /* Process ReadFile requests on sockets through ws2_32.dll */
+        WSAOVERLAPPED *lpOverlapped = (WSAOVERLAPPED *) io_status;
+        DWORD bytes_recvd = 0, flags = 0;
+        WSABUF wsabuf[1];
+
+        wsabuf[0].len = length;
+        wsabuf[0].buf = buffer;
+        if (hEvent != NULL)
+        {
+            lpOverlapped->hEvent = hEvent;
+            if (offset)
+            {
+                lpOverlapped->u.s.Offset = offset->u.LowPart;
+                lpOverlapped->u.s.OffsetHigh = offset->u.HighPart;
+            }
+        }
+        result = pWSARecv( (SOCKET) hFile, &wsabuf[0], 1, &bytes_recvd, &flags,
+                           (hEvent == NULL ? NULL : lpOverlapped), NULL);
+        if (result == 0)
+            status = STATUS_SUCCESS;
+        else
+            status = WSAErrorToNtStatus(pWSAGetLastError());
+
+        total = bytes_recvd;
+        cvalue = 0; /* Completion handled by WSARecv() */
+        goto done; /* Make sure NtQueueApcThread is called */
+    }
 
     for (;;)
     {
@@ -755,7 +866,6 @@ err:
     return status;
 }
 
-
 /******************************************************************************
  *  NtReadFileScatter   [NTDLL.@]
  *  ZwReadFileScatter   [NTDLL.@]
@@ -967,6 +1077,35 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
         status = STATUS_SUCCESS;
         goto done;
     }
+    else if (type == FD_TYPE_SOCKET && LoadWSA())
+    {
+        /* Process WriteFile requests on sockets through ws2_32.dll */
+        WSAOVERLAPPED *lpOverlapped = (WSAOVERLAPPED *) io_status;
+        DWORD bytes_sent = 0;
+        WSABUF wsabuf[1];
+
+        wsabuf[0].len = length;
+        wsabuf[0].buf = (void*) buffer;
+        if (hEvent != NULL)
+        {
+            lpOverlapped->hEvent = hEvent;
+            if (offset)
+            {
+                lpOverlapped->u.s.Offset = offset->u.LowPart;
+                lpOverlapped->u.s.OffsetHigh = offset->u.HighPart;
+            }
+        }
+        result = pWSASend( (SOCKET) hFile, &wsabuf[0], 1, &bytes_sent, 0,
+                           (hEvent == NULL ? NULL : lpOverlapped), NULL );
+        if (result == 0)
+            status = STATUS_SUCCESS;
+        else
+            status = WSAErrorToNtStatus(pWSAGetLastError());
+
+        total = bytes_sent;
+        cvalue = 0; /* Completion handled by WSASend() */
+        goto done; /* Make sure NtQueueApcThread is called */
+    }
 
     for (;;)
     {
-- 
1.7.1

