From d656cb2024a5018cce53a40540a0a6d4e566c38e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 31 Oct 2022 12:46:08 -0600 Subject: [PATCH] ws2_32: Track SO_EXCLUSIVEADDRUSE option value. --- dlls/ws2_32/socket.c | 20 ++++++++++++++------ dlls/ws2_32/tests/sock.c | 1 + include/wine/afd.h | 2 ++ server/sock.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 2f115f02e48..9e447f29d8c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1818,6 +1818,11 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl if (!ret && *optlen < sizeof(DWORD)) *optlen = 1; return ret; + case SO_EXCLUSIVEADDRUSE: + ret = server_getsockopt( s, IOCTL_AFD_WINE_GET_SO_EXCLUSIVEADDRUSE, optval, optlen ); + if (!ret && *optlen < sizeof(DWORD)) *optlen = 1; + return ret; + case SO_SNDBUF: if (*optlen < sizeof(DWORD) || !optval) { @@ -3215,6 +3220,15 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int memcpy( &value, optval, min( optlen, sizeof(value) )); return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_REUSEADDR, (char *)&value, sizeof(value) ); + case SO_EXCLUSIVEADDRUSE: + if (!optval) + { + SetLastError( WSAEFAULT ); + return SOCKET_ERROR; + } + memcpy( &value, optval, min( optlen, sizeof(value) )); + return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_EXCLUSIVEADDRUSE, (char *)&value, sizeof(value) ); + case SO_SNDBUF: if (optlen < 0) optlen = 4; return server_setsockopt( s, IOCTL_AFD_WINE_SET_SO_SNDBUF, optval, optlen ); @@ -3240,12 +3254,6 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int SetLastError( ERROR_SUCCESS ); return 0; - /* Stops two sockets from being bound to the same port. Always happens - * on unix systems, so just drop it. */ - case SO_EXCLUSIVEADDRUSE: - TRACE("Ignoring SO_EXCLUSIVEADDRUSE, is always set.\n"); - return 0; - /* After a ConnectEx call succeeds, the socket can't be used with half of the * normal winsock functions on windows. We don't have that problem. */ case SO_UPDATE_CONNECT_CONTEXT: diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 852cdd88dc7..00f4327bb3b 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1209,6 +1209,7 @@ static void test_set_getsockopt(void) {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_DONTROUTE, TRUE, {1, 1, 1}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_RCVTIMEO, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR, TRUE, {1, 1, 4}, {0, 0xdead0001, 0}, TRUE, TRUE}, + {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, TRUE, {1, 1, 4}, {0, 0xdead0001, 0}, TRUE, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_SNDBUF, FALSE, {1, 2, 4}, {0xdeadbe00, 0xdead0000}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_SNDTIMEO, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_OPENTYPE, FALSE, {1, 2, 4}, {0}, TRUE}, diff --git a/include/wine/afd.h b/include/wine/afd.h index 993730cacdb..b34a7b7318e 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -283,6 +283,8 @@ C_ASSERT( sizeof(struct afd_get_events_params) == 56 ); #define IOCTL_AFD_WINE_SET_IP_RECVTTL WINE_AFD_IOC(294) #define IOCTL_AFD_WINE_GET_IP_RECVTOS WINE_AFD_IOC(295) #define IOCTL_AFD_WINE_SET_IP_RECVTOS WINE_AFD_IOC(296) +#define IOCTL_AFD_WINE_GET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(297) +#define IOCTL_AFD_WINE_SET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(298) struct afd_iovec { diff --git a/server/sock.c b/server/sock.c index 2156a1a12c2..88215650757 100644 --- a/server/sock.c +++ b/server/sock.c @@ -256,6 +256,7 @@ struct sock unsigned int bound : 1; /* is the socket bound? */ unsigned int reset : 1; /* did we get a TCP reset? */ unsigned int reuseaddr : 1; /* winsock SO_REUSEADDR option value */ + unsigned int exclusiveaddruse : 1; /* winsock SO_EXCLUSIVEADDRUSE option value */ }; static int is_tcp_socket( struct sock *sock ) @@ -1697,6 +1698,7 @@ static struct sock *create_socket(void) sock->bound = 0; sock->reset = 0; sock->reuseaddr = 0; + sock->exclusiveaddruse = 0; sock->rcvbuf = 0; sock->sndbuf = 0; sock->rcvtimeo = 0; @@ -3103,6 +3105,21 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; } + case IOCTL_AFD_WINE_SET_SO_EXCLUSIVEADDRUSE: + { + int exclusive; + + if (get_req_data_size() < sizeof(exclusive)) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return; + } + + exclusive = *(int *)get_req_data(); + sock->exclusiveaddruse = !!exclusive; + return; + } + case IOCTL_AFD_WINE_GET_SO_SNDBUF: { int sndbuf = sock->sndbuf; @@ -3205,6 +3222,21 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; } + case IOCTL_AFD_WINE_GET_SO_EXCLUSIVEADDRUSE: + { + int exclusive; + + if (!get_reply_max_size()) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return; + } + + exclusive = sock->exclusiveaddruse; + set_reply_data( &exclusive, min( sizeof(exclusive), get_reply_max_size() )); + return; + } + case IOCTL_AFD_POLL: { if (get_reply_max_size() < get_req_data_size())