[PATCH 5/5] ws2_32: Handle SO_RCVTIMEO in the server.

Zebediah Figura z.figura12 at gmail.com
Fri Jun 25 20:21:09 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ws2_32/socket.c     | 10 +++++-----
 dlls/ws2_32/tests/sock.c |  8 ++++----
 include/wine/afd.h       |  2 ++
 server/sock.c            | 40 +++++++++++++++++++++++++++++++++-------
 4 files changed, 44 insertions(+), 16 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 7ed48124a5a..15c9d0cc940 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2289,6 +2289,8 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
             return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_RCVBUF, optval, optlen );
 
         case WS_SO_RCVTIMEO:
+            return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_RCVTIMEO, optval, optlen );
+
         case WS_SO_SNDTIMEO:
         {
             INT64 timeout;
@@ -3565,6 +3567,9 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
         case WS_SO_RCVBUF:
             return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_RCVBUF, optval, optlen );
 
+        case WS_SO_RCVTIMEO:
+            return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_RCVTIMEO, optval, optlen );
+
         /* Some options need some conversion before they can be sent to
          * setsockopt. The conversions are done here, then they will fall through
          * to the general case. Special options that are not passed to
@@ -3631,13 +3636,8 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
             TRACE("setting global SO_OPENTYPE = 0x%x\n", *((const int*)optval) );
             return 0;
 
-#ifdef SO_RCVTIMEO
-        case WS_SO_RCVTIMEO:
-#endif
 #ifdef SO_SNDTIMEO
         case WS_SO_SNDTIMEO:
-#endif
-#if defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)
             if (optval && optlen == sizeof(UINT32)) {
                 /* WinSock passes milliseconds instead of struct timeval */
                 tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000;
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index ccaa04e4ef5..a3f7e002ce7 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -10919,7 +10919,7 @@ static void test_timeout(void)
     WSASetLastError(0xdeadbeef);
     ret = getsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, &len);
     ok(!ret, "expected success\n");
-    todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError());
+    ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError());
     ok(len == sizeof(timeout), "got size %u\n", len);
     ok(!timeout, "got timeout %u\n", timeout);
 
@@ -10927,15 +10927,15 @@ static void test_timeout(void)
     WSASetLastError(0xdeadbeef);
     ret = setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
     ok(!ret, "expected success\n");
-    todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError());
+    ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError());
 
     timeout = 0xdeadbeef;
     len = sizeof(timeout);
     WSASetLastError(0xdeadbeef);
     ret = getsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, &len);
     ok(!ret, "expected success\n");
-    todo_wine ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError());
-    todo_wine ok(timeout == 100, "got timeout %u\n", timeout);
+    ok(!WSAGetLastError(), "got error %u\n", WSAGetLastError());
+    ok(timeout == 100, "got timeout %u\n", timeout);
 
     WSASetLastError(0xdeadbeef);
     ret = recv(client, &buffer, 1, 0);
diff --git a/include/wine/afd.h b/include/wine/afd.h
index 0692394459e..c4f7c7a6413 100644
--- a/include/wine/afd.h
+++ b/include/wine/afd.h
@@ -171,6 +171,8 @@ struct afd_get_events_params
 #define IOCTL_AFD_WINE_SET_SO_OOBINLINE     CTL_CODE(FILE_DEVICE_NETWORK, 228, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define IOCTL_AFD_WINE_SET_SO_RCVBUF        CTL_CODE(FILE_DEVICE_NETWORK, 229, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define IOCTL_AFD_WINE_GET_SO_RCVBUF        CTL_CODE(FILE_DEVICE_NETWORK, 230, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_AFD_WINE_SET_SO_RCVTIMEO      CTL_CODE(FILE_DEVICE_NETWORK, 231, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_AFD_WINE_GET_SO_RCVTIMEO      CTL_CODE(FILE_DEVICE_NETWORK, 232, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
 struct afd_create_params
 {
diff --git a/server/sock.c b/server/sock.c
index 8bad31efdd1..d86b88b0564 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -208,6 +208,7 @@ struct sock
     union win_sockaddr  addr;        /* socket name */
     int                 addr_len;    /* socket name length */
     unsigned int        rcvbuf;      /* advisory recv buffer size */
+    unsigned int        rcvtimeo;    /* receive timeout in ms */
     unsigned int        rd_shutdown : 1; /* is the read end shut down? */
     unsigned int        wr_shutdown : 1; /* is the write end shut down? */
     unsigned int        wr_shutdown_pending : 1; /* is a write shutdown pending? */
@@ -1388,6 +1389,7 @@ static struct sock *create_socket(void)
     sock->nonblocking = 0;
     sock->bound = 0;
     sock->rcvbuf = 0;
+    sock->rcvtimeo = 0;
     init_async_queue( &sock->read_q );
     init_async_queue( &sock->write_q );
     init_async_queue( &sock->ifchange_q );
@@ -2619,6 +2621,35 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
         return 0;
     }
 
+    case IOCTL_AFD_WINE_GET_SO_RCVTIMEO:
+    {
+        DWORD rcvtimeo = sock->rcvtimeo;
+
+        if (get_reply_max_size() < sizeof(rcvtimeo))
+        {
+            set_error( STATUS_BUFFER_TOO_SMALL );
+            return 0;
+        }
+
+        set_reply_data( &rcvtimeo, sizeof(rcvtimeo) );
+        return 1;
+    }
+
+    case IOCTL_AFD_WINE_SET_SO_RCVTIMEO:
+    {
+        DWORD rcvtimeo;
+
+        if (get_req_data_size() < sizeof(rcvtimeo))
+        {
+            set_error( STATUS_BUFFER_TOO_SMALL );
+            return 0;
+        }
+        rcvtimeo = *(DWORD *)get_req_data();
+
+        sock->rcvtimeo = rcvtimeo;
+        return 0;
+    }
+
     default:
         set_error( STATUS_NOT_SUPPORTED );
         return 0;
@@ -3029,19 +3060,14 @@ DECL_HANDLER(recv_socket)
     /* recv() returned EWOULDBLOCK, i.e. no data available yet */
     if (status == STATUS_DEVICE_NOT_READY && !sock->nonblocking)
     {
-#ifdef SO_RCVTIMEO
-        struct timeval tv;
-        socklen_t len = sizeof(tv);
-
         /* Set a timeout on the async if necessary.
          *
          * We want to do this *only* if the client gave us STATUS_DEVICE_NOT_READY.
          * If the client gave us STATUS_PENDING, it expects the async to always
          * block (it was triggered by WSARecv*() with a valid OVERLAPPED
          * structure) and for the timeout not to be respected. */
-        if (is_fd_overlapped( fd ) && !getsockopt( get_unix_fd( fd ), SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, &len ))
-            timeout = tv.tv_sec * -10000000 + tv.tv_usec * -10;
-#endif
+        if (is_fd_overlapped( fd ))
+            timeout = sock->rcvtimeo * -10000;
 
         status = STATUS_PENDING;
     }
-- 
2.30.2




More information about the wine-devel mailing list