A new attempt on WSACleanup

Bruno Jesus 00cpxxx at gmail.com
Tue Nov 24 12:07:28 CST 2015


After some time struggling with the server I finally managed to
produce a working version of the idea of bringing all sockets from
server to winsock and then closing all of them. Tested with 1026
sockets and seems to work as expected by bringing 128 sockets per
request from the server.

This is certainly too much for code freeze but I plan to send after
it, feedback is very much welcome since mistakes are always possible
when working after midnight.

Best wishes,
Bruno
-------------- next part --------------
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index d31f0b4..28a9ab1 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -1004,8 +1004,8 @@ static inline DWORD NtStatusToWSAError( const DWORD status )
     {
     case STATUS_SUCCESS:                    wserr = 0;                     break;
     case STATUS_PENDING:                    wserr = WSA_IO_PENDING;        break;
+    case STATUS_INVALID_HANDLE:
     case STATUS_OBJECT_TYPE_MISMATCH:       wserr = WSAENOTSOCK;           break;
-    case STATUS_INVALID_HANDLE:             wserr = WSAEBADF;              break;
     case STATUS_INVALID_PARAMETER:          wserr = WSAEINVAL;             break;
     case STATUS_PIPE_DISCONNECTED:          wserr = WSAESHUTDOWN;          break;
     case STATUS_NETWORK_BUSY:               wserr = WSAEALREADY;           break;
@@ -1109,6 +1109,50 @@ static void _sync_sock_state(SOCKET s)
     (void)_is_blocking(s, &dummy);
 }
 
+static SOCKET* _get_all_sockets(void)
+{
+#define MAX_SOCKS_PER_REQ 128
+    unsigned int index = 0, sock_count = 0, buf_sz;
+    SOCKET *socks, *new_socks;
+    NTSTATUS status;
+
+    /* +1 for list end */
+    buf_sz = sizeof(SOCKET) * (MAX_SOCKS_PER_REQ + 1);
+    socks = HeapAlloc(GetProcessHeap(), 0, buf_sz);
+    if (!socks) return NULL;
+
+    do
+    {
+        SERVER_START_REQ( get_socks_batch )
+        {
+            req->start_index = index;
+            wine_server_set_reply( req, socks + sock_count, sizeof(SOCKET) * MAX_SOCKS_PER_REQ );
+            status = wine_server_call( req );
+            if (!status)
+            {
+                sock_count += reply->sock_count;
+                socks[sock_count] = -1;
+                index = reply->enum_index;
+
+                /* Enumeration ended? */
+                if (!reply->sock_count) return socks;
+
+                buf_sz += sizeof(SOCKET) * MAX_SOCKS_PER_REQ;
+                new_socks = HeapReAlloc(GetProcessHeap(), 0, socks, buf_sz);
+                if (!new_socks) break;
+                socks = new_socks;
+            }
+            else break;
+        }
+        SERVER_END_REQ;
+    }
+    while(1);
+
+    HeapFree(GetProcessHeap(), 0, socks);
+    return NULL;
+#undef MAX_SOCKS_PER_REQ
+}
+
 static void _get_sock_errors(SOCKET s, int *events)
 {
     SERVER_START_REQ( get_socket_event )
@@ -1487,13 +1531,27 @@ int WINAPI WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
  */
 INT WINAPI WSACleanup(void)
 {
-    if (num_startup) {
-        num_startup--;
-        TRACE("pending cleanups: %d\n", num_startup);
-        return 0;
+    if (!num_startup)
+    {
+        SetLastError(WSANOTINITIALISED);
+        return SOCKET_ERROR;
     }
-    SetLastError(WSANOTINITIALISED);
-    return SOCKET_ERROR;
+    if (num_startup == 1)
+    {
+        SOCKET *fds = _get_all_sockets();
+        int i;
+
+        if (fds)
+        {
+            for (i = 0; fds[i] != -1; i++)
+                WS_closesocket(fds[i]);
+            HeapFree(GetProcessHeap(), 0, fds);
+            TRACE("closed %d sockets\n", i);
+        }
+    }
+    num_startup--;
+    TRACE("pending cleanups: %d\n", num_startup);
+    return 0;
 }
 
 
@@ -2117,7 +2175,7 @@ static BOOL ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, i
     if (status)
     {
         unsigned int err = NtStatusToWSAError( status );
-        SetLastError( err == WSAEBADF ? WSAENOTSOCK : err );
+        SetLastError( err );
         return FALSE;
     }
 
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 8676b07..8245ad4 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1123,7 +1123,6 @@ static void test_WithWSAStartup(void)
     ok(res == 0, "WSAStartup() failed unexpectedly: %d\n", res);
 
     /* show that sockets are destroyed automatically after WSACleanup */
-    todo_wine {
     SetLastError(0xdeadbeef);
     res = send(src, "TEST", 4, 0);
     error = WSAGetLastError();
@@ -1135,7 +1134,6 @@ static void test_WithWSAStartup(void)
     error = WSAGetLastError();
     ok(res == SOCKET_ERROR, "closesocket should have failed\n");
     ok(error == WSAENOTSOCK, "expected 10038, got %d\n", error);
-    }
 
     closesocket(src);
     closesocket(dst);
diff --git a/server/protocol.def b/server/protocol.def
index aa37c66..1852d73 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1232,6 +1232,14 @@ enum server_fd_type
     file_pos_t   count;         /* count of bytes to unlock */
 @END
 
+/* Get socket handles batch */
+ at REQ(get_socks_batch)
+    unsigned int start_index;
+ at REPLY
+    unsigned int enum_index;
+    unsigned int sock_count;
+    VARARG(socks,ints);
+ at END
 
 /* Create a socket */
 @REQ(create_socket)
diff --git a/server/sock.c b/server/sock.c
index 1767dea..160a946 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -1207,6 +1207,23 @@ static void sock_destroy_ifchange_q( struct sock *sock )
     }
 }
 
+DECL_HANDLER(get_socks_batch)
+{
+    SOCKET socks[128];
+    obj_handle_t handle;
+    unsigned int enum_index = req->start_index, sock_index = 0, max_socks;
+
+    max_socks = min(sizeof(socks) / sizeof(socks[0]), get_reply_max_size() / sizeof(socks[0]));
+    while ( (handle = enumerate_handles(current->process, &sock_ops, &enum_index)) )
+    {
+        socks[sock_index++] = handle;
+        if (sock_index == max_socks) break;
+    }
+    reply->enum_index = enum_index;
+    reply->sock_count = sock_index;
+    set_reply_data( socks, sock_index * sizeof(socks[0]) );
+}
+
 /* create a socket */
 DECL_HANDLER(create_socket)
 {


More information about the wine-devel mailing list