[PATCH resend] ws2_32: Support setting SO_ERROR

Alex Henrie alexhenrie24 at gmail.com
Mon Nov 22 23:06:02 CST 2021


Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
This patch was previously assigned to Zeb Figura, but dropped off the
patches list without review.
---
 dlls/ws2_32/socket.c     |  4 +---
 dlls/ws2_32/tests/sock.c | 10 ++++++++--
 include/wine/afd.h       |  1 +
 server/sock.c            | 38 +++++++++++++++++++++++++++-----------
 4 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 2db441bee3c..2c2eabc09fa 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2750,9 +2750,7 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
         }
 
         case SO_ERROR:
-            FIXME( "SO_ERROR, stub!\n" );
-            SetLastError( WSAENOPROTOOPT );
-            return -1;
+            return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_ERROR, optval, optlen );
 
         case SO_KEEPALIVE:
             return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_KEEPALIVE, optval, optlen );
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 02713a7c625..76f4f1ef8a2 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1289,7 +1289,6 @@ static void test_set_getsockopt(void)
     SetLastError(0xdeadbeef);
     i = 1234;
     err = setsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &i, size);
-todo_wine
     ok( !err && !WSAGetLastError(),
         "got %d with %d (expected 0 with 0)\n",
         err, WSAGetLastError());
@@ -1300,7 +1299,14 @@ todo_wine
     ok( !err && !WSAGetLastError(),
         "got %d with %d (expected 0 with 0)\n",
         err, WSAGetLastError());
-todo_wine
+    ok (i == 1234, "got %d (expected 1234)\n", i);
+
+    SetLastError(0xdeadbeef);
+    i = 4321;
+    err = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &i, &size);
+    ok( !err && !WSAGetLastError(),
+        "got %d with %d (expected 0 with 0)\n",
+        err, WSAGetLastError());
     ok (i == 1234, "got %d (expected 1234)\n", i);
 
     /* Test invalid optlen */
diff --git a/include/wine/afd.h b/include/wine/afd.h
index 3b8bdcb9e5d..9382e2acf2f 100644
--- a/include/wine/afd.h
+++ b/include/wine/afd.h
@@ -238,6 +238,7 @@ struct afd_get_events_params
 #define IOCTL_AFD_WINE_SET_IP_RECVTTL                   WINE_AFD_IOC(294)
 #define IOCTL_AFD_WINE_GET_IP_RECVTOS                   WINE_AFD_IOC(295)
 #define IOCTL_AFD_WINE_SET_IP_RECVTOS                   WINE_AFD_IOC(296)
+#define IOCTL_AFD_WINE_SET_SO_ERROR                     WINE_AFD_IOC(297)
 
 struct afd_create_params
 {
diff --git a/server/sock.c b/server/sock.c
index c9b71137c4c..cfb65e0b54c 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -191,6 +191,7 @@ struct sock
     unsigned int        message;     /* message to send */
     obj_handle_t        wparam;      /* message wparam (socket handle) */
     int                 errors[AFD_POLL_BIT_COUNT]; /* event errors */
+    unsigned int        last_error;  /* most recent error code */
     timeout_t           connect_time;/* time the socket was connected */
     struct sock        *deferred;    /* socket that waits for a deferred accept */
     struct async_queue  read_q;      /* queue for asynchronous reads */
@@ -963,6 +964,7 @@ static void post_socket_event( struct sock *sock, enum afd_poll_bit event_bit, i
         sock->pending_events |= event;
         sock->reported_events |= event;
         sock->errors[event_bit] = error;
+        sock->last_error = sock_get_error( error );
     }
 }
 
@@ -978,6 +980,7 @@ static void sock_dispatch_events( struct sock *sock, enum connection_state prevs
         {
             post_socket_event( sock, AFD_POLL_BIT_CONNECT, 0 );
             sock->errors[AFD_POLL_BIT_CONNECT_ERR] = 0;
+            sock->last_error = 0;
         }
         if (event & (POLLERR | POLLHUP))
             post_socket_event( sock, AFD_POLL_BIT_CONNECT_ERR, error );
@@ -1441,6 +1444,7 @@ static struct sock *create_socket(void)
     init_async_queue( &sock->connect_q );
     init_async_queue( &sock->poll_q );
     memset( sock->errors, 0, sizeof(sock->errors) );
+    sock->last_error = 0;
     list_init( &sock->accept_list );
     return sock;
 }
@@ -2675,7 +2679,6 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
     {
         int error;
         socklen_t len = sizeof(error);
-        unsigned int i;
 
         if (get_reply_max_size() < sizeof(error))
         {
@@ -2689,19 +2692,32 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
             return;
         }
 
-        if (!error)
+        if (error)
+            sock->last_error = sock_get_error( error );
+
+        set_reply_data( &sock->last_error, sizeof(sock->last_error) );
+        return;
+    }
+
+    case IOCTL_AFD_WINE_SET_SO_ERROR:
+    {
+        int error;
+        socklen_t len = sizeof(error);
+
+        if (get_req_data_size() < sizeof(sock->last_error))
         {
-            for (i = 0; i < ARRAY_SIZE( sock->errors ); ++i)
-            {
-                if (sock->errors[i])
-                {
-                    error = sock_get_error( sock->errors[i] );
-                    break;
-                }
-            }
+            set_error( STATUS_BUFFER_TOO_SMALL );
+            return;
+        }
+
+        /* clear the native error, if any */
+        if (getsockopt( unix_fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len ) < 0)
+        {
+            set_error( sock_get_ntstatus( errno ) );
+            return;
         }
 
-        set_reply_data( &error, sizeof(error) );
+        sock->last_error = *(unsigned int *)get_req_data();
         return;
     }
 
-- 
2.34.0




More information about the wine-devel mailing list