ws2_32: Handle SO_RCVTIMEO in the server.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-06-29 11:43:20 -05:00 committed by Alexandre Julliard
parent 8aaf9e6460
commit f4df896e06
4 changed files with 44 additions and 16 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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
{

View File

@ -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;
}