diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index be986912f03..d216542ba93 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -8349,8 +8349,9 @@ static void test_sioAddressListChange(void) struct in_addr net_address; WSAOVERLAPPED overlapped; struct hostent *h; - DWORD num_bytes, error; - SOCKET sock; + DWORD num_bytes, error, tick; + SOCKET sock, sock2, sock3; + WSAEVENT event2, event3; int acount; int ret; @@ -8397,9 +8398,6 @@ todo_wine sock = socket(AF_INET, 0, IPPROTO_TCP); ok(sock != INVALID_SOCKET, "socket() failed\n"); - memset(&bindAddress, 0, sizeof(bindAddress)); - bindAddress.sin_family = AF_INET; - bindAddress.sin_addr.s_addr = net_address.s_addr; SetLastError(0xdeadbeef); ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); ok (!ret, "bind() failed with error %d\n", GetLastError()); @@ -8419,9 +8417,6 @@ todo_wine sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); ok(sock != INVALID_SOCKET, "socket() failed\n"); - memset(&bindAddress, 0, sizeof(bindAddress)); - bindAddress.sin_family = AF_INET; - bindAddress.sin_addr.s_addr = net_address.s_addr; SetLastError(0xdeadbeef); ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); ok (!ret, "bind() failed with error %d\n", GetLastError()); @@ -8442,9 +8437,6 @@ todo_wine sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); ok(sock != INVALID_SOCKET, "socket() failed\n"); - memset(&bindAddress, 0, sizeof(bindAddress)); - bindAddress.sin_family = AF_INET; - bindAddress.sin_addr.s_addr = net_address.s_addr; SetLastError(0xdeadbeef); ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); ok (!ret, "bind() failed with error %d\n", GetLastError()); @@ -8461,6 +8453,40 @@ todo_wine CloseHandle(overlapped.hEvent); closesocket(sock); + /* When the socket is overlapped non-blocking and the list change is requested without + * an overlapped structure the error will be different. */ + sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + ok(sock != INVALID_SOCKET, "socket() failed\n"); + + SetLastError(0xdeadbeef); + ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); + ok (!ret, "bind() failed with error %d\n", GetLastError()); + set_blocking(sock, FALSE); + + SetLastError(0xdeadbeef); + ret = WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, NULL, NULL); + error = GetLastError(); + ok (ret == SOCKET_ERROR, "WSAIoctl(SIO_ADDRESS_LIST_CHANGE) failed with error %d\n", error); + ok (error == WSAEWOULDBLOCK, "expected 10035, got %d\n", error); + + closesocket(sock); + + /* Misuse of the API by using a blocking socket and not using an overlapped structure, + * this leads to a hang forever. */ + if (0) + { + sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + + SetLastError(0xdeadbeef); + bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); + + set_blocking(sock, TRUE); + WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, NULL, NULL); + /* hang */ + + closesocket(sock); + } + if (!winetest_interactive) { skip("Cannot test SIO_ADDRESS_LIST_CHANGE, interactive tests must be enabled\n"); @@ -8470,35 +8496,61 @@ todo_wine /* Bind an overlapped socket to the first found network interface */ sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); ok(sock != INVALID_SOCKET, "Expected socket to return a valid socket\n"); - if (sock == INVALID_SOCKET) - { - skip("Cannot test SIO_ADDRESS_LIST_CHANGE, socket creation failed with %u\n", - WSAGetLastError()); - return; - } - memset(&bindAddress, 0, sizeof(bindAddress)); - bindAddress.sin_family = AF_INET; - bindAddress.sin_addr.s_addr = net_address.s_addr; + sock2 = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + ok(sock2 != INVALID_SOCKET, "Expected socket to return a valid socket\n"); + sock3 = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + ok(sock3 != INVALID_SOCKET, "Expected socket to return a valid socket\n"); + ret = bind(sock, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); - if (ret != 0) - { - skip("Cannot test SIO_ADDRESS_LIST_CHANGE, failed to bind, error %u\n", WSAGetLastError()); - goto end; - } + ok(!ret, "bind failed unexpectedly\n"); + ret = bind(sock2, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); + ok(!ret, "bind failed unexpectedly\n"); + ret = bind(sock3, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); + ok(!ret, "bind failed unexpectedly\n"); + + set_blocking(sock2, FALSE); + set_blocking(sock3, FALSE); /* Wait for address changes, request that the user connects/disconnects an interface */ memset(&overlapped, 0, sizeof(overlapped)); overlapped.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); ret = WSAIoctl(sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, &overlapped, NULL); ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); - ok(WSAGetLastError() == WSA_IO_PENDING, "Expected pending last error %d\n", WSAGetLastError()); + ok(WSAGetLastError() == WSA_IO_PENDING, "Expected pending last error, got %d\n", WSAGetLastError()); + + ret = WSAIoctl(sock2, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &num_bytes, NULL, NULL); + ok(ret == SOCKET_ERROR, "WSAIoctl succeeded unexpectedly\n"); + ok(WSAGetLastError() == WSAEWOULDBLOCK, "Expected would block last error, got %d\n", WSAGetLastError()); + + event2 = WSACreateEvent(); + event3 = WSACreateEvent(); + ret = WSAEventSelect (sock2, event2, FD_ADDRESS_LIST_CHANGE); + ok(!ret, "WSAEventSelect failed with %d\n", WSAGetLastError()); + /* sock3 did not request SIO_ADDRESS_LIST_CHANGE but it is trying to wait anyway */ + ret = WSAEventSelect (sock3, event3, FD_ADDRESS_LIST_CHANGE); + ok(!ret, "WSAEventSelect failed with %d\n", WSAGetLastError()); + trace("Testing socket-based ipv4 address list change notification. Please connect/disconnect or" - " change the ipv4 address of any of the local network interfaces (10 second timeout).\n"); - ret = WaitForSingleObject(overlapped.hEvent, 10000); + " change the ipv4 address of any of the local network interfaces (15 second timeout).\n"); + tick = GetTickCount(); + ret = WaitForSingleObject(overlapped.hEvent, 15000); ok(ret == WAIT_OBJECT_0, "failed to get overlapped event %u\n", ret); -end: + ret = WaitForSingleObject(event2, 500); +todo_wine + ok(ret == WAIT_OBJECT_0, "failed to get change event %u\n", ret); + + ret = WaitForSingleObject(event3, 500); + ok(ret == WAIT_TIMEOUT, "unexpected change event\n"); + + trace("Spent %d ms waiting.\n", GetTickCount() - tick); + + WSACloseEvent(event2); + WSACloseEvent(event3); + closesocket(sock); + closesocket(sock2); + closesocket(sock3); } static void test_synchronous_WSAIoctl(void) diff --git a/include/winsock2.h b/include/winsock2.h index 24f0ea37848..a2563f4df2e 100644 --- a/include/winsock2.h +++ b/include/winsock2.h @@ -101,6 +101,15 @@ extern "C" { #define FD_ACCEPT_BIT 3 #define FD_CONNECT_BIT 4 #define FD_CLOSE_BIT 5 +#define FD_QOS_BIT 6 +#define FD_GROUP_QOS_BIT 7 +#define FD_ROUTING_INTERFACE_CHANGE_BIT 8 +#define FD_ADDRESS_LIST_CHANGE_BIT 9 + +#define FD_QOS 0x00000040 +#define FD_GROUP_QOS 0x00000080 +#define FD_ROUTING_INTERFACE_CHANGE 0x00000100 +#define FD_ADDRESS_LIST_CHANGE 0x00000200 /* Constants for LPCONDITIONPROC */ #define CF_ACCEPT 0x0000