diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 562d05ed4be..ce71e25d63d 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -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; diff --git a/include/wine/afd.h b/include/wine/afd.h index f2a5abf726d..44a8b1a5ff9 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -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 { diff --git a/server/sock.c b/server/sock.c index 9a99e512c0d..befa9117c13 100644 --- a/server/sock.c +++ b/server/sock.c @@ -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; }