ws2_32: Handle SO_SNDTIMEO 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 23:25:43 -05:00 committed by Alexandre Julliard
parent 35288d6537
commit 20c1990372
3 changed files with 39 additions and 73 deletions

View File

@ -913,34 +913,6 @@ static int convert_sockopt(INT *level, INT *optname)
return 0;
}
/* Utility: get the SO_RCVTIMEO or SO_SNDTIMEO socket option
* from an fd and return the value converted to milli seconds
* or 0 if there is an infinite time out */
static inline INT64 get_rcvsnd_timeo( int fd, BOOL is_recv)
{
struct timeval tv;
socklen_t len = sizeof(tv);
int optname, res;
if (is_recv)
#ifdef SO_RCVTIMEO
optname = SO_RCVTIMEO;
#else
return 0;
#endif
else
#ifdef SO_SNDTIMEO
optname = SO_SNDTIMEO;
#else
return 0;
#endif
res = getsockopt(fd, SOL_SOCKET, optname, &tv, &len);
if (res < 0)
return 0;
return (UINT64)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
int
convert_socktype_w2u(int windowssocktype) {
unsigned int i;
@ -2283,23 +2255,8 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_SNDBUF, optval, optlen );
case WS_SO_SNDTIMEO:
{
INT64 timeout;
return server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_SNDTIMEO, optval, optlen );
if (!optlen || *optlen < sizeof(int)|| !optval)
{
SetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
return SOCKET_ERROR;
timeout = get_rcvsnd_timeo(fd, optname == WS_SO_RCVTIMEO);
*(int *)optval = timeout <= UINT_MAX ? timeout : UINT_MAX;
release_sock_fd( s, fd );
return ret;
}
case WS_SO_TYPE:
{
int sock_type;
@ -3504,7 +3461,6 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
{
int fd;
int woptval;
struct timeval tval;
struct ip_mreq_source mreq_source;
TRACE("(socket %04lx, %s, optval %s, optlen %d)\n", s,
@ -3567,6 +3523,9 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
case WS_SO_SNDBUF:
return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_SNDBUF, optval, optlen );
case WS_SO_SNDTIMEO:
return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_SNDTIMEO, optval, optlen );
/* SO_DEBUG is a privileged operation, ignore it. */
case WS_SO_DEBUG:
TRACE("Ignoring SO_DEBUG\n");
@ -3607,27 +3566,6 @@ 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_SNDTIMEO
case WS_SO_SNDTIMEO:
if (optval && optlen == sizeof(UINT32)) {
/* WinSock passes milliseconds instead of struct timeval */
tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000;
tval.tv_sec = *(const UINT32*)optval / 1000;
/* min of 500 milliseconds */
if (tval.tv_sec == 0 && tval.tv_usec && tval.tv_usec < 500000)
tval.tv_usec = 500000;
optlen = sizeof(struct timeval);
optval = (char*)&tval;
} else if (optlen == sizeof(struct timeval)) {
WARN("SO_SND/RCVTIMEO for %d bytes: assuming unixism\n", optlen);
} else {
WARN("SO_SND/RCVTIMEO for %d bytes is weird: ignored\n", optlen);
return 0;
}
convert_sockopt(&level, &optname);
break;
#endif
case WS_SO_RANDOMIZE_PORT:
FIXME("Ignoring WS_SO_RANDOMIZE_PORT\n");
return 0;

View File

@ -177,6 +177,8 @@ struct afd_get_events_params
#define IOCTL_AFD_WINE_SET_SO_REUSEADDR CTL_CODE(FILE_DEVICE_NETWORK, 234, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_SET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 235, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_GET_SO_SNDBUF CTL_CODE(FILE_DEVICE_NETWORK, 236, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_GET_SO_SNDTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 237, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_AFD_WINE_SET_SO_SNDTIMEO CTL_CODE(FILE_DEVICE_NETWORK, 238, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct afd_create_params
{

View File

@ -210,6 +210,7 @@ struct sock
unsigned int rcvbuf; /* advisory recv buffer size */
unsigned int sndbuf; /* advisory send buffer size */
unsigned int rcvtimeo; /* receive timeout in ms */
unsigned int sndtimeo; /* send 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? */
@ -1392,6 +1393,7 @@ static struct sock *create_socket(void)
sock->rcvbuf = 0;
sock->sndbuf = 0;
sock->rcvtimeo = 0;
sock->sndtimeo = 0;
init_async_queue( &sock->read_q );
init_async_queue( &sock->write_q );
init_async_queue( &sock->ifchange_q );
@ -2697,6 +2699,35 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
return 0;
}
case IOCTL_AFD_WINE_GET_SO_SNDTIMEO:
{
DWORD sndtimeo = sock->sndtimeo;
if (get_reply_max_size() < sizeof(sndtimeo))
{
set_error( STATUS_BUFFER_TOO_SMALL );
return 0;
}
set_reply_data( &sndtimeo, sizeof(sndtimeo) );
return 1;
}
case IOCTL_AFD_WINE_SET_SO_SNDTIMEO:
{
DWORD sndtimeo;
if (get_req_data_size() < sizeof(sndtimeo))
{
set_error( STATUS_BUFFER_TOO_SMALL );
return 0;
}
sndtimeo = *(DWORD *)get_req_data();
sock->sndtimeo = sndtimeo;
return 0;
}
default:
set_error( STATUS_NOT_SUPPORTED );
return 0;
@ -3217,19 +3248,14 @@ DECL_HANDLER(send_socket)
/* send() returned EWOULDBLOCK or a short write, i.e. cannot send all data yet */
if (status == STATUS_DEVICE_NOT_READY && !sock->nonblocking)
{
#ifdef SO_SNDTIMEO
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 WSASend*() 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_SNDTIMEO, (char *)&tv, &len ))
timeout = tv.tv_sec * -10000000 + tv.tv_usec * -10;
#endif
if (is_fd_overlapped( fd ))
timeout = (timeout_t)sock->sndtimeo * -10000;
status = STATUS_PENDING;
}