From 3a762c7717a2d06b83525fa3f709aa57bf8466d2 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sun, 6 Sep 2015 12:41:17 +0200
Subject: [PATCH] ws2_32: Invalidate client-side file descriptor cache in
 WSACleanup.

---
 dlls/ntdll/ntdll.spec          |  1 +
 dlls/ntdll/server.c            |  8 ++++++++
 dlls/ntdll/unix/loader.c       |  1 +
 dlls/ntdll/unix/server.c       | 20 ++++++++++++++++++++
 dlls/ntdll/unix/unix_private.h |  1 +
 dlls/ntdll/unixlib.h           |  1 +
 dlls/ws2_32/socket.c           |  1 +
 dlls/ws2_32/tests/sock.c       |  5 +----
 include/wine/server.h          |  1 +
 9 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 2d4ced7e63e..598f57404b4 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -1582,6 +1582,7 @@
 
 # Server interface
 @ cdecl -norelay wine_server_call(ptr)
+@ cdecl wine_server_close_fds_by_type(long)
 @ cdecl wine_server_fd_to_handle(long long long ptr)
 @ cdecl wine_server_handle_to_fd(long long ptr ptr)
 @ cdecl wine_server_release_fd(long long)
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index a3ad3e68871..d6cd0b4ce22 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -120,6 +120,14 @@ int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *uni
     return unix_funcs->server_handle_to_fd( handle, access, unix_fd, options );
 }
 
+ /***********************************************************************
+ *           wine_server_close_fds_by_type
+ */
+void CDECL wine_server_close_fds_by_type( enum server_fd_type type )
+{
+    unix_funcs->server_remove_fds_from_cache_by_type( type );
+}
+
 
 /***********************************************************************
  *           wine_server_release_fd   (NTDLL.@)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 8366e3a9989..649c03f116f 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -1442,6 +1442,7 @@ static struct unix_funcs unix_funcs =
     exec_process,
     wine_server_call,
     server_send_fd,
+    server_remove_fds_from_cache_by_type,
     server_fd_to_handle,
     server_handle_to_fd,
     server_release_fd,
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index cb014c91230..1687d633a4c 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -1012,6 +1012,26 @@ static int remove_fd_from_cache( HANDLE handle )
     return fd;
 }
 
+/***********************************************************************
+ *           server_remove_fds_from_cache_by_type
+ */
+void CDECL server_remove_fds_from_cache_by_type( enum server_fd_type type )
+{
+    union fd_cache_entry cache;
+    unsigned int entry, idx;
+
+    for (entry = 0; entry < FD_CACHE_ENTRIES; entry++)
+    {
+        if (!fd_cache[entry]) continue;
+        for (idx = 0; idx < FD_CACHE_BLOCK_SIZE; idx++)
+        {
+            cache.data = InterlockedCompareExchange64( &fd_cache[entry][idx].data, 0, 0 );
+            if (cache.s.type != type || cache.s.fd == 0) continue;
+            if (InterlockedCompareExchange64( &fd_cache[entry][idx].data, 0, cache.data ) != cache.data) continue;
+            close( cache.s.fd - 1 );
+        }
+    }
+}
 
 /***********************************************************************
  *           server_get_unix_fd
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index dad33ee5e9f..00b718dfb7e 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -114,6 +114,7 @@ extern ssize_t CDECL virtual_locked_recvmsg( int fd, struct msghdr *hdr, int fla
 extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN;
 
 extern void CDECL server_send_fd( int fd ) DECLSPEC_HIDDEN;
+extern void CDECL server_remove_fds_from_cache_by_type( enum server_fd_type type ) DECLSPEC_HIDDEN;
 extern NTSTATUS CDECL server_fd_to_handle( int fd, unsigned int access, unsigned int attributes,
                                            HANDLE *handle ) DECLSPEC_HIDDEN;
 extern NTSTATUS CDECL server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h
index 715af516867..12c2ea15b5c 100644
--- a/dlls/ntdll/unixlib.h
+++ b/dlls/ntdll/unixlib.h
@@ -100,6 +100,7 @@ struct unix_funcs
     /* server functions */
     unsigned int  (CDECL *server_call)( void *req_ptr );
     void          (CDECL *server_send_fd)( int fd );
+    void          (CDECL *server_remove_fds_from_cache_by_type)( enum server_fd_type type );
     NTSTATUS      (CDECL *server_fd_to_handle)( int fd, unsigned int access, unsigned int attributes,
                                                 HANDLE *handle );
     NTSTATUS      (CDECL *server_handle_to_fd)( HANDLE handle, unsigned int access, int *unix_fd,
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 6bf4140ba00..4f0c3c3adfa 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -1740,6 +1740,7 @@ INT WINAPI WSACleanup(void)
 
     if (!--num_startup)
     {
+        wine_server_close_fds_by_type( FD_TYPE_SOCKET );
         SERVER_START_REQ(socket_cleanup)
         {
             wine_server_call( req );
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 9fe89d9dba3..c2e1379fe6f 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1250,10 +1250,7 @@ static void test_WithWSAStartup(void)
             SetLastError(0xdeadbeef);
             res = getsockname(sock, (struct sockaddr *)&saddr, &size);
             error = WSAGetLastError();
-            if (j == 2 || (j == 0 && i == 0))
-                todo_wine ok(res == SOCKET_ERROR, "Test[%d]: getsockname should have failed\n", i);
-            else
-                ok(res == SOCKET_ERROR, "Test[%d]: getsockname should have failed\n", i);
+            ok(res == SOCKET_ERROR, "Test[%d]: getsockname should have failed\n", i);
             todo_wine ok(error == WSAENOTSOCK, "Test[%d]: expected 10038, got %d\n", i, error);
         }
     }
diff --git a/include/wine/server.h b/include/wine/server.h
index ac5dcc6f8bc..5cf52887516 100644
--- a/include/wine/server.h
+++ b/include/wine/server.h
@@ -54,6 +54,7 @@ extern void CDECL wine_server_send_fd( int fd );
 extern int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle );
 extern int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, unsigned int *options );
 extern void CDECL wine_server_release_fd( HANDLE handle, int unix_fd );
+extern void CDECL wine_server_close_fds_by_type( enum server_fd_type type );
 
 /* do a server call and set the last error code */
 static inline unsigned int wine_server_call_err( void *req_ptr )
-- 
2.27.0

