From: "Erich E. Hoover" <ehoover@mines.edu>
Subject: [PATCH 5/5] ws2_32: Use completion information to send AcceptEx completions (try 2).
Message-Id: <CAEU2+vo5grX1gnk3fWyrCpOvowFTQCJU3Ete_aXoDqjycc8ArQ@mail.gmail.com>
Date: Thu, 3 May 2012 16:54:26 -0600

Real Name:
    Erich Hoover

Description:
    This patch uses the newly added completion information parameter
in order to send AcceptEx completions even when the originating handle
has closed.  The patch fixes an issue with the WoW launcher and the
Diablo 3 installer (Bug #27657) where the applications do not receive
the ERROR_OPERATION_ABORTED completions that they need in order to
properly proceed.  Like patch 4, this version the patch has been
updated to use the FILE_COMPLETION_INFORMATION structure.  This
version therefore requires fewer headers and no-longer requiring
typecasting of the completion key (removing the need for a helper
function).

Changelog:
    ws2_32: Use completion information to send AcceptEx completions.

From 394f8d20e61b152d23bab52ca6f15231970923ef Mon Sep 17 00:00:00 2001
From: Erich Hoover <ehoover@mines.edu>
Date: Thu, 3 May 2012 16:40:03 -0600
Subject: ws2_32: Use completion information to send AcceptEx completions.

---
 dlls/ws2_32/socket.c     |   25 ++++++++++++----------
 dlls/ws2_32/tests/sock.c |   50 +++++++++++++++++++++++-----------------------
 2 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 471ff63..12d09b9 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -273,15 +273,16 @@ typedef struct ws2_async
 
 typedef struct ws2_accept_async
 {
-    HANDLE              listen_socket;
-    HANDLE              accept_socket;
-    LPOVERLAPPED        user_overlapped;
-    ULONG_PTR           cvalue;
-    PVOID               buf;      /* buffer to write data to */
-    int                 data_len;
-    int                 local_len;
-    int                 remote_len;
-    struct ws2_async    *read;
+    HANDLE                              listen_socket;
+    HANDLE                              accept_socket;
+    LPOVERLAPPED                        user_overlapped;
+    ULONG_PTR                           cvalue;
+    FILE_COMPLETION_INFORMATION         comp_info; /* information for sending file completions */
+    PVOID                               buf;      /* buffer to write data to */
+    int                                 data_len;
+    int                                 local_len;
+    int                                 remote_len;
+    struct ws2_async                   *read;
 } ws2_accept_async;
 
 /****************************************************************/
@@ -1634,7 +1635,8 @@ static NTSTATUS WS2_async_accept_recv( void *arg, IO_STATUS_BLOCK *iosb, NTSTATU
     if (wsa->user_overlapped->hEvent)
         SetEvent(wsa->user_overlapped->hEvent);
     if (wsa->cvalue)
-        WS_AddCompletion( HANDLE2SOCKET(wsa->listen_socket), wsa->cvalue, iosb->u.Status, iosb->Information );
+        NtSetIoCompletion( wsa->comp_info.CompletionPort, wsa->comp_info.CompletionKey, wsa->cvalue,
+                           iosb->u.Status, iosb->Information );
 
     *apc = ws2_async_accept_apc;
     return status;
@@ -1695,6 +1697,7 @@ static NTSTATUS WS2_async_accept( void *arg, IO_STATUS_BLOCK *iosb, NTSTATUS sta
     if (!wsa->read)
         goto finish;
 
+    wsa->comp_info = *comp;
     SERVER_START_REQ( register_async )
     {
         req->type           = ASYNC_TYPE_READ;
@@ -1718,7 +1721,7 @@ finish:
     if (wsa->user_overlapped->hEvent)
         SetEvent(wsa->user_overlapped->hEvent);
     if (wsa->cvalue)
-        WS_AddCompletion( HANDLE2SOCKET(wsa->listen_socket), wsa->cvalue, iosb->u.Status, iosb->Information );
+        NtSetIoCompletion( comp->CompletionPort, comp->CompletionKey, wsa->cvalue, iosb->u.Status, iosb->Information );
 
     *apc = ws2_async_accept_apc;
     return status;
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index e9814e3..29616b2 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -5494,11 +5494,11 @@ static void test_completion_port(void)
 
     bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100);
     ok(bret == FALSE, "failed to get completion status %u\n", bret);
-    todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
-    todo_wine ok(key == 125, "Key is %lu\n", key);
-    todo_wine ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
-    todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp);
-    todo_wine ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
+    ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
+    ok(key == 125, "Key is %lu\n", key);
+    ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
+    ok(olp == &ov, "Overlapped structure is at %p\n", olp);
+    ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
 
     SetLastError(0xdeadbeef);
     key = 0xdeadbeef;
@@ -5537,11 +5537,11 @@ static void test_completion_port(void)
 
     bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100);
     ok(bret == FALSE, "failed to get completion status %u\n", bret);
-    todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
-    todo_wine ok(key == 125, "Key is %lu\n", key);
-    todo_wine ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
-    todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp);
-    todo_wine ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
+    ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
+    ok(key == 125, "Key is %lu\n", key);
+    ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
+    ok(olp == &ov, "Overlapped structure is at %p\n", olp);
+    ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
 
     SetLastError(0xdeadbeef);
     key = 0xdeadbeef;
@@ -5596,11 +5596,11 @@ static void test_completion_port(void)
     olp = (WSAOVERLAPPED *)0xdeadbeef;
     bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100);
     ok(bret == FALSE, "failed to get completion status %u\n", bret);
-    todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
-    todo_wine ok(key == 125, "Key is %lu\n", key);
-    todo_wine ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
-    todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp);
-    todo_wine ok(olp && olp->Internal == (ULONG)STATUS_CANCELLED, "Internal status is %lx\n", olp ? olp->Internal : 0);
+    ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
+    ok(key == 125, "Key is %lu\n", key);
+    ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
+    ok(olp == &ov, "Overlapped structure is at %p\n", olp);
+    ok(olp && olp->Internal == (ULONG)STATUS_CANCELLED, "Internal status is %lx\n", olp ? olp->Internal : 0);
 
     SetLastError(0xdeadbeef);
     key = 0xdeadbeef;
@@ -5663,11 +5663,11 @@ static void test_completion_port(void)
 
     bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100);
     ok(bret == FALSE, "failed to get completion status %u\n", bret);
-    todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
-    todo_wine ok(key == 125, "Key is %lu\n", key);
-    todo_wine ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
-    todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp);
-    todo_wine ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
+    ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
+    ok(key == 125, "Key is %lu\n", key);
+    ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
+    ok(olp == &ov, "Overlapped structure is at %p\n", olp);
+    ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
 
     SetLastError(0xdeadbeef);
     key = 0xdeadbeef;
@@ -5719,11 +5719,11 @@ static void test_completion_port(void)
 
     bret = GetQueuedCompletionStatus(io_port, &num_bytes, &key, &olp, 100);
     ok(bret == FALSE, "failed to get completion status %u\n", bret);
-    todo_wine ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
-    todo_wine ok(key == 125, "Key is %lu\n", key);
-    todo_wine ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
-    todo_wine ok(olp == &ov, "Overlapped structure is at %p\n", olp);
-    todo_wine ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
+    ok(GetLastError() == ERROR_OPERATION_ABORTED, "Last error was %d\n", GetLastError());
+    ok(key == 125, "Key is %lu\n", key);
+    ok(num_bytes == 0, "Number of bytes transferred is %u\n", num_bytes);
+    ok(olp == &ov, "Overlapped structure is at %p\n", olp);
+    ok(olp && (olp->Internal == (ULONG)STATUS_CANCELLED), "Internal status is %lx\n", olp ? olp->Internal : 0);
 
     SetLastError(0xdeadbeef);
     key = 0xdeadbeef;
-- 
1.7.5.4