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:
parent
35288d6537
commit
20c1990372
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue