File 0006-ws2_32-tests-Add-test-for-AF_UNIX-sockets.patch of Package wine

From c50d1720ae950428185a314d1468bbb1bc6a172b Mon Sep 17 00:00:00 2001
From: Ally Sommers <dropbear.sh@gmail.com>
Date: Sun, 7 May 2023 09:15:49 +0200
Subject: [PATCH 6/9] ws2_32/tests: Add test for AF_UNIX sockets

---
 dlls/ws2_32/tests/sock.c | 292 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 292 insertions(+)

diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index a3fb6744235..a16052c620f 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -29,6 +29,7 @@
 #include <iphlpapi.h>
 #include <ws2tcpip.h>
 #include <wsipx.h>
+#include <afunix.h>
 #include <wsnwlink.h>
 #include <mswsock.h>
 #include <mstcpip.h>
@@ -14520,6 +14521,296 @@ static void test_valid_handle(void)
     closesocket(server);
 }
 
+static void test_afunix(void)
+{
+    SOCKET listener, client, server = 0;
+    SOCKADDR_UN addr = { AF_UNIX, "test_afunix.sock" };
+    char serverBuf[] = "ws2_32/AF_UNIX socket test";
+    char clientBuf[sizeof(serverBuf)] = { 0 };
+
+    char paths[4][sizeof(addr.sun_path)] = { "./tmp.sock", "../tmp.sock" };
+    char dosPath[sizeof(addr.sun_path)];
+    WCHAR dosWidePath[sizeof(addr.sun_path)];
+    UNICODE_STRING ntPath = { 0 };
+    SOCKADDR_UN outAddr = { 0 };
+    int outAddrSize = sizeof(outAddr);
+    SOCKADDR_UN truncatedAddr = { 0 };
+    ULONG zero = 0;
+    ULONG one = 1;
+    int ret;
+
+    /* Test connection and send/recv */
+    listener = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (listener == INVALID_SOCKET && GetLastError() == WSAEAFNOSUPPORT)
+    {
+        win_skip("AF_UNIX sockets are unsupported, skipping...\n");
+        return;
+    }
+
+    ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n",
+        GetLastError());
+
+    ret = bind(listener, (SOCKADDR *)&addr, 0);
+    ok(ret && GetLastError() == WSAEFAULT, "Incorrect error: %lu\n", GetLastError());
+    ret = bind(listener, (SOCKADDR *)&addr, 2);
+    ok(!ret, "Could not bind Unix socket: %lu\n", GetLastError());
+    ret = listen(listener, 1);
+    ok(!ret, "Could not listen on Unix socket: %lu\n", GetLastError());
+    closesocket(listener);
+
+    listener = socket(AF_UNIX, SOCK_STREAM, 0);
+    ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n",
+        GetLastError());
+    ret = bind(listener, (SOCKADDR *)&addr, 3);
+    ok(!ret, "Could not bind Unix socket: %lu\n", GetLastError());
+
+    memcpy(&truncatedAddr, &addr, 3);
+    ret = getsockname(listener, (SOCKADDR *)&outAddr, &outAddrSize);
+    ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError());
+    ok(!memcmp(truncatedAddr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)),
+        "getsockname returned incorrect path '%s' for provided path '%s'\n",
+        outAddr.sun_path,
+        truncatedAddr.sun_path);
+    ok(outAddrSize == sizeof(outAddr.sun_family) + strlen(outAddr.sun_path) + 1,
+        "getsockname returned incorrect size '%d' for provided path '%s'\n",
+        outAddrSize,
+        truncatedAddr.sun_path);
+    closesocket(listener);
+    ret = DeleteFileA(truncatedAddr.sun_path);
+    ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError());
+    ok(GetFileAttributesA(truncatedAddr.sun_path) == INVALID_FILE_ATTRIBUTES &&
+        GetLastError() == ERROR_FILE_NOT_FOUND,
+        "Failed to delete socket file at path '%s'\n",
+        truncatedAddr.sun_path);
+
+    listener = socket(AF_UNIX, SOCK_STREAM, 0);
+    ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n",
+        GetLastError());
+
+    ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN));
+    ok(!ret, "Could not bind Unix socket: %lu\n", GetLastError());
+
+    ret = listen(listener, 1);
+    ok(!ret, "Could not listen on Unix socket: %lu\n", GetLastError());
+
+    client = socket(AF_UNIX, SOCK_STREAM, 0);
+    ok(client != INVALID_SOCKET, "Failed to create second Unix socket: %lu\n",
+        GetLastError());
+
+    ret = ioctlsocket(client, FIONBIO, &one);
+    ok(!ret, "Could not set AF_UNIX socket to nonblocking: %lu; skipping connection\n", GetLastError());
+    if (!ret)
+    {
+        ret = connect(client, (SOCKADDR *)&addr, sizeof(addr));
+        ok(!ret || (ret == SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK),
+            "Error when connecting to Unix socket: %lu\n",
+            GetLastError());
+        server = accept(listener, NULL, NULL);
+        ok(server != INVALID_SOCKET, "Could not accept Unix socket connection: %lu\n",
+            GetLastError());
+        ret = ioctlsocket(client, FIONBIO, &zero);
+        ok(!ret, "Could not set AF_UNIX socket to blocking: %lu\n", GetLastError());
+    }
+
+    ret = send(server, serverBuf, sizeof(serverBuf), 0);
+    ok(ret == sizeof(serverBuf), "Incorrect return value from send: %d\n", ret);
+    ret = recv(client, clientBuf, sizeof(serverBuf), 0);
+    ok(ret == sizeof(serverBuf), "Incorrect return value from recv: %d\n", ret);
+    ok(!memcmp(serverBuf, clientBuf, sizeof(serverBuf)), "Data mismatch over Unix socket\n");
+
+    memset(clientBuf, 0, sizeof(clientBuf));
+
+    ret = sendto(server, serverBuf, sizeof(serverBuf), 0, NULL, 0);
+    ok(ret == sizeof(serverBuf), "Incorrect return value from sendto: %d\n", ret);
+    ret = recvfrom(client, clientBuf, sizeof(serverBuf), 0, NULL, 0);
+    ok(ret == sizeof(serverBuf), "Incorrect return value from recvfrom: %d\n", ret);
+    ok(!memcmp(serverBuf, clientBuf, sizeof(serverBuf)), "Data mismatch over Unix socket\n");
+
+    memset(serverBuf, 0, sizeof(serverBuf));
+
+    ret = send(client, clientBuf, sizeof(clientBuf), 0);
+    ok(ret == sizeof(clientBuf), "Incorrect return value from send: %d\n", ret);
+    ret = recv(server, serverBuf, sizeof(clientBuf), 0);
+    ok(ret == sizeof(serverBuf), "Incorrect return value from recv: %d\n", ret);
+    ok(!memcmp(serverBuf, clientBuf, sizeof(clientBuf)), "Data mismatch over Unix socket\n");
+
+    memset(serverBuf, 0, sizeof(serverBuf));
+
+    ret = sendto(client, clientBuf, sizeof(clientBuf), 0, NULL, 0);
+    ok(ret == sizeof(clientBuf), "Incorrect return value from sendto: %d\n", ret);
+    ret = recvfrom(server, serverBuf, sizeof(clientBuf), 0, NULL, 0);
+    ok(ret == sizeof(serverBuf), "Incorrect return value from recvfrom: %d\n", ret);
+    ok(!memcmp(serverBuf, clientBuf, sizeof(clientBuf)), "Data mismatch over Unix socket\n");
+
+    closesocket(listener);
+    closesocket(client);
+    closesocket(server);
+
+    /* Test socket file deletion */
+    ret = DeleteFileA("test_afunix.sock");
+    ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError());
+    ok(GetFileAttributesA("test_afunix.sock") == INVALID_FILE_ATTRIBUTES &&
+        GetLastError() == ERROR_FILE_NOT_FOUND,
+        "Failed to delete socket file at path '%s'\n",
+        addr.sun_path);
+
+    /* Test failure modes */
+    listener = socket(AF_UNIX, SOCK_STREAM, 0);
+    ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n",
+        GetLastError());
+    ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN));
+    ok(!ret, "Could not bind Unix socket to path '%s': %lu\n", addr.sun_path, GetLastError());
+    closesocket(listener);
+    listener = socket(AF_UNIX, SOCK_STREAM, 0);
+    ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n",
+        GetLastError());
+    ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN));
+    ok(ret && GetLastError() == WSAEADDRINUSE,
+        "Bound Unix socket to path '%s' despite existing socket file: %lu\n",
+        addr.sun_path,
+        GetLastError());
+    closesocket(listener);
+    ret = DeleteFileA(addr.sun_path);
+    ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError());
+    ok(GetFileAttributesA("test_afunix.sock") == INVALID_FILE_ATTRIBUTES &&
+        GetLastError() == ERROR_FILE_NOT_FOUND,
+        "Failed to delete socket file at path '%s'\n",
+        addr.sun_path);
+
+    /* Test different path types (relative, NT, etc.) */
+    GetTempPathA(sizeof(paths[0]) - 1, paths[2]);
+    strcat(paths[2], "tmp.sock");
+    MultiByteToWideChar(CP_ACP, 0, paths[2], -1, dosWidePath, sizeof(dosPath));
+    RtlDosPathNameToNtPathName_U(dosWidePath, &ntPath, NULL, NULL);
+    RtlUnicodeToMultiByteN(paths[3], sizeof(addr.sun_path) - 1, NULL, ntPath.Buffer, ntPath.Length);
+
+    for (int i = 0; i < sizeof(paths) / sizeof(paths[0]); i++)
+    {
+        memcpy(addr.sun_path, paths[i], sizeof(paths[i]));
+
+        listener = socket(AF_UNIX, SOCK_STREAM, 0);
+        ok(listener != INVALID_SOCKET, "Could not create Unix socket: %lu\n",
+            GetLastError());
+
+        ret = bind(listener, (SOCKADDR *)&addr, sizeof(SOCKADDR_UN));
+        ok(!ret, "Could not bind Unix socket to path '%s': %lu\n", addr.sun_path, GetLastError());
+
+        ret = listen(listener, 1);
+        ok(!ret, "Could not listen on Unix socket: %lu\n", GetLastError());
+
+        client = socket(AF_UNIX, SOCK_STREAM, 0);
+        ok(client != INVALID_SOCKET, "Failed to create second Unix socket: %lu\n",
+            GetLastError());
+
+        ret = ioctlsocket(client, FIONBIO, &one);
+        ok(!ret, "Could not set AF_UNIX socket to nonblocking: %lu; skipping connection\n", GetLastError());
+        if (!ret)
+        {
+            ret = connect(client, (SOCKADDR *)&addr, sizeof(addr));
+            ok(!ret || (ret == SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK),
+                "Error when connecting to Unix socket: %lu\n",
+                GetLastError());
+            server = accept(listener, NULL, NULL);
+            ok(server != INVALID_SOCKET, "Could not accept Unix socket connection: %lu\n",
+                GetLastError());
+            ret = ioctlsocket(client, FIONBIO, &zero);
+            ok(!ret, "Could not set AF_UNIX socket to blocking: %lu\n", GetLastError());
+        }
+
+        memset(&outAddr, 0, sizeof(outAddr));
+        outAddrSize = sizeof(outAddr);
+        ret = getsockname(listener, (SOCKADDR *)&outAddr, &outAddrSize);
+        ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError());
+        ok(!memcmp(addr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)),
+            "getsockname returned incorrect path '%s' for provided path '%s'\n",
+            outAddr.sun_path,
+            addr.sun_path);
+        ok(outAddrSize == sizeof(outAddr.sun_family) + strlen(outAddr.sun_path) + 1,
+            "getsockname returned incorrect size '%d' for provided path '%s'\n",
+            outAddrSize,
+            addr.sun_path);
+
+        memset(&outAddr, 0, sizeof(outAddr));
+        outAddrSize = sizeof(outAddr);
+        ret = getsockname(client, (SOCKADDR *)&outAddr, &outAddrSize);
+        ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError());
+        ok(!memcmp((char[108]){0}, outAddr.sun_path, sizeof(addr.sun_path)),
+            "getsockname returned incorrect path '%s' for provided path '%s'\n",
+            outAddr.sun_path,
+            addr.sun_path);
+        ok(outAddrSize == sizeof(outAddr),
+            "getsockname returned incorrect size '%d' for provided path '%s'\n",
+            outAddrSize,
+            addr.sun_path);
+
+        memset(&outAddr, 0, sizeof(outAddr));
+        outAddrSize = sizeof(outAddr);
+        ret = getsockname(server, (SOCKADDR *)&outAddr, &outAddrSize);
+        ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError());
+        ok(!memcmp(addr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)),
+            "getsockname returned incorrect path '%s' for provided path '%s'\n",
+            outAddr.sun_path,
+            addr.sun_path);
+        ok(outAddrSize == sizeof(outAddr.sun_family) + strlen(outAddr.sun_path) + 1,
+            "getsockname returned incorrect size '%d' for provided path '%s'\n",
+            outAddrSize,
+            addr.sun_path);
+
+        memset(&outAddr, 0, sizeof(outAddr));
+        outAddrSize = sizeof(outAddr);
+        ret = getpeername(listener, (SOCKADDR *)&outAddr, &outAddrSize);
+        ok(ret == -1, "Got info on Unix socket: %lu\n", GetLastError());
+        ok(GetLastError() == WSAENOTCONN,
+            "Incorrect error returned from getpeername on Unix socket: %ld\n",
+            GetLastError());
+        ok(!memcmp((char[108]){0}, outAddr.sun_path, sizeof(addr.sun_path)),
+            "getpeername returned incorrect path '%s' for provided path '%s'\n",
+            outAddr.sun_path,
+            addr.sun_path);
+        ok(outAddrSize == sizeof(outAddr),
+            "getpeername returned incorrect size '%d' for provided path '%s'\n",
+            outAddrSize,
+            addr.sun_path);
+
+        memset(&outAddr, 0, sizeof(outAddr));
+        outAddrSize = sizeof(outAddr);
+        ret = getpeername(client, (SOCKADDR *)&outAddr, &outAddrSize);
+        ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError());
+        ok(!memcmp(addr.sun_path, outAddr.sun_path, sizeof(addr.sun_path)),
+            "getpeername returned incorrect path '%s' for provided path '%s'\n",
+            outAddr.sun_path,
+            addr.sun_path);
+        ok(outAddrSize == sizeof(outAddr),
+            "getpeername returned incorrect size '%d' for provided path '%s'\n",
+            outAddrSize,
+            addr.sun_path);
+
+        memset(&outAddr, 0, sizeof(outAddr));
+        outAddrSize = sizeof(outAddr);
+        ret = getpeername(server, (SOCKADDR *)&outAddr, &outAddrSize);
+        ok(!ret, "Could not get info on Unix socket: %lu\n", GetLastError());
+        ok(!memcmp((char[108]){0}, outAddr.sun_path, sizeof(addr.sun_path)),
+            "getpeername returned incorrect path '%s' for provided path '%s'\n",
+            outAddr.sun_path,
+            addr.sun_path);
+        ok(outAddrSize == sizeof(outAddr),
+            "getpeername returned incorrect size '%d' for provided path '%s'\n",
+            outAddrSize,
+            addr.sun_path);
+
+        closesocket(listener);
+        closesocket(client);
+        closesocket(server);
+
+        ret = DeleteFileA(addr.sun_path);
+        ok(ret, "DeleteFileA on socket file failed: %lu\n", GetLastError());
+        ok(GetFileAttributesA(addr.sun_path) == INVALID_FILE_ATTRIBUTES &&
+            GetLastError() == ERROR_FILE_NOT_FOUND,
+            "Failed to delete socket file at path '%s'\n",
+            addr.sun_path);
+    }
+}
+
 START_TEST( sock )
 {
     int i;
@@ -14606,6 +14897,7 @@ START_TEST( sock )
     test_broadcast();
     test_send_buffering();
     test_valid_handle();
+    test_afunix();
 
     /* There is apparently an obscure interaction between this test and
      * test_WSAGetOverlappedResult().
-- 
2.50.0

openSUSE Build Service is sponsored by