[PATCH v2 1/7] ws2_32: Handle SO_RCVTIMEO in the server.
Zebediah Figura
z.figura12 at gmail.com
Mon Jun 28 22:39:18 CDT 2021
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
v2: cast timeout to 64 bits before multiplying
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..94dbafe44ee 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 = (timeout_t)sock->rcvtimeo * -10000;
status = STATUS_PENDING;
}
--
2.30.2
More information about the wine-devel
mailing list