From 6a8836ca45c963a134858b91c4b4fc456a018f23 Mon Sep 17 00:00:00 2001
From: Erich Hoover <ehoover@mines.edu>
Date: Sat, 25 Sep 2010 21:15:21 -0600
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 3dc5358..aa30a65 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,75 @@ mode_t FILE_umask = 0;
 #define SECSPERDAY         86400
 #define SECS_1601_TO_1970  ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
 
+/* NtStatusToWSAError in ws2_32/socket.c correspondes 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 void 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;
+    RtlInitUnicodeString( &wstr, wsalibW );
+    LdrLoadDll( NULL, 0, &wstr, &hModule );
+    RtlInitAnsiString( &str, (LPCSTR) &cWSAGetLastError );
+    LdrGetProcedureAddress( hModule, &str, 0, (void**)&pWSAGetLastError );
+    RtlInitAnsiString( &str, (LPCSTR) &cWSARecv );
+    LdrGetProcedureAddress( hModule, &str, 0, (void**)&pWSARecv );
+    RtlInitAnsiString( &str, (LPCSTR) &cWSASend );
+    LdrGetProcedureAddress( hModule, &str, 0, (void**)&pWSASend );
+}
 
 /**************************************************************************
  *                 FILE_CreateFile                    (internal)
@@ -618,6 +690,40 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
         status = total ? STATUS_SUCCESS : STATUS_END_OF_FILE;
         goto done;
     }
+    else if (type == FD_TYPE_SOCKET)
+    {
+        /* Process ReadFile requests on sockets through ws2_32 */
+        LPWSAOVERLAPPED_COMPLETION_ROUTINE lpOverlappedCompletionRoutine = NULL;
+        WSAOVERLAPPED *lpOverlapped = (WSAOVERLAPPED *) io_status;
+        DWORD bytes_recvd = 0, flags = 0;
+        WSABUF wsabuf[1];
+
+        LoadWSA();
+        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;
+            }
+        }
+        if (cvalue != (ULONG_PTR)lpOverlapped)
+            lpOverlappedCompletionRoutine = (LPWSAOVERLAPPED_COMPLETION_ROUTINE) cvalue;
+        result = pWSARecv( (SOCKET) hFile, &wsabuf[0], 1, &bytes_recvd, &flags,
+                           (hEvent == NULL ? NULL : lpOverlapped),
+                            lpOverlappedCompletionRoutine);
+        if (result == 0)
+            status = STATUS_SUCCESS;
+        else
+            status = WSAErrorToNtStatus(pWSAGetLastError());
+
+        total = bytes_recvd;
+        cvalue = 0; /* completion handled by WSARecv */
+        goto done;
+    }
 
     for (;;)
     {
@@ -755,7 +861,6 @@ err:
     return status;
 }
 
-
 /******************************************************************************
  *  NtReadFileScatter   [NTDLL.@]
  *  ZwReadFileScatter   [NTDLL.@]
@@ -967,6 +1072,40 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
         status = STATUS_SUCCESS;
         goto done;
     }
+    else if (type == FD_TYPE_SOCKET)
+    {
+        /* Process WriteFile requests on sockets through ws2_32 */
+        LPWSAOVERLAPPED_COMPLETION_ROUTINE lpOverlappedCompletionRoutine = NULL;
+        WSAOVERLAPPED *lpOverlapped = (WSAOVERLAPPED *) io_status;
+        DWORD bytes_sent = 0;
+        WSABUF wsabuf[1];
+
+        LoadWSA();
+        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;
+            }
+        }
+        if (cvalue != (ULONG_PTR)lpOverlapped)
+            lpOverlappedCompletionRoutine = (LPWSAOVERLAPPED_COMPLETION_ROUTINE) cvalue;
+        result = pWSASend( (SOCKET) hFile, &wsabuf[0], 1, &bytes_sent, 0,
+                           (hEvent == NULL ? NULL : lpOverlapped),
+                           lpOverlappedCompletionRoutine );
+        if (result == 0)
+            status = STATUS_SUCCESS;
+        else
+            status = WSAErrorToNtStatus(pWSAGetLastError());
+
+        total = bytes_sent;
+        cvalue = 0; /* completion handled by WSASend */
+        goto done;
+    }
 
     for (;;)
     {
-- 
1.7.0.4

