From 344cddb63af183570165942d333aa588360c589b Mon Sep 17 00:00:00 2001 From: Bruno Jesus <00cpxxx@gmail.com> Date: Fri, 6 Nov 2015 00:40:34 +0800 Subject: [PATCH] ws2_32/tests: Add WSAPoll() tests. Signed-off-by: Bruno Jesus <00cpxxx@gmail.com> Signed-off-by: Alexandre Julliard --- dlls/ws2_32/tests/sock.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 29e20c3c93b..8676b070c1d 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -74,6 +74,7 @@ static int (WINAPI *pWSALookupServiceEnd)(HANDLE); static int (WINAPI *pWSALookupServiceNextW)(HANDLE,DWORD,LPDWORD,LPWSAQUERYSETW); static int (WINAPI *pWSAEnumNameSpaceProvidersA)(LPDWORD,LPWSANAMESPACE_INFOA); static int (WINAPI *pWSAEnumNameSpaceProvidersW)(LPDWORD,LPWSANAMESPACE_INFOW); +static int (WINAPI *pWSAPoll)(WSAPOLLFD *,ULONG,INT); /**************** Structs and typedefs ***************/ @@ -1169,6 +1170,7 @@ static void Init (void) pWSALookupServiceNextW = (void *)GetProcAddress(hws2_32, "WSALookupServiceNextW"); pWSAEnumNameSpaceProvidersA = (void *)GetProcAddress(hws2_32, "WSAEnumNameSpaceProvidersA"); pWSAEnumNameSpaceProvidersW = (void *)GetProcAddress(hws2_32, "WSAEnumNameSpaceProvidersW"); + pWSAPoll = (void *)GetProcAddress(hws2_32, "WSAPoll"); ok ( WSAStartup ( ver, &data ) == 0, "WSAStartup failed\n" ); tls = TlsAlloc(); @@ -6330,6 +6332,225 @@ end: WSACloseEvent(ov.hEvent); } +#define POLL_CLEAR() ix = 0 +#define POLL_SET(s, ev) {fds[ix].fd = s; fds[ix++].events = ev;} +#define POLL_ISSET(s, rev) poll_isset(fds, ix, s, rev) +static BOOL poll_isset(WSAPOLLFD *fds, int max, SOCKET s, int rev) +{ + int k; + for (k = 0; k < max; k++) + if (fds[k].fd == s && (fds[k].revents == rev)) return TRUE; + return FALSE; +} + +static void test_WSAPoll(void) +{ + int ix, ret, err, poll_timeout; + SOCKET fdListen, fdRead, fdWrite; + struct sockaddr_in address; + socklen_t len; + static char tmp_buf[1024]; + WSAPOLLFD fds[16]; + HANDLE thread_handle; + DWORD id; + + if (!pWSAPoll) /* >= Vista */ + { + skip("WSAPoll is unsupported, some tests will be skipped.\n"); + return; + } + + /* Invalid parameters test */ + SetLastError(0xdeadbeef); + ret = pWSAPoll(NULL, 0, 0); + err = GetLastError(); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ok(err == WSAEINVAL, "expected 10022, got %d\n", err); + SetLastError(0xdeadbeef); + ret = pWSAPoll(NULL, 1, 0); + err = GetLastError(); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ok(err == WSAEFAULT, "expected 10014, got %d\n", err); + SetLastError(0xdeadbeef); + ret = pWSAPoll(NULL, 0, 1); + err = GetLastError(); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ok(err == WSAEINVAL, "expected 10022, got %d\n", err); + SetLastError(0xdeadbeef); + ret = pWSAPoll(NULL, 1, 1); + err = GetLastError(); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ok(err == WSAEFAULT, "expected 10014, got %d\n", err); + + /* WSAPoll() tries to mime the unix poll() call. The following tests do: + * - check if a connection attempt ended with success or error; + * - check if a pending connection is waiting for acceptance; + * - check for data to read, availability for write and OOB data + */ + memset(&address, 0, sizeof(address)); + address.sin_addr.s_addr = inet_addr("127.0.0.1"); + address.sin_family = AF_INET; + len = sizeof(address); + fdListen = setup_server_socket(&address, &len); + poll_timeout = 100; + + /* When no events are pending poll returns 0 with no error */ + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 0, "expected 0, got %d\n", ret); + + /* Test listening socket connection attempt notifications */ + fdWrite = setup_connector_socket(&address, len, TRUE); + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN | POLLOUT); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdListen, POLLRDNORM), "fdListen socket events incorrect\n"); + len = sizeof(address); + fdRead = accept(fdListen, (struct sockaddr*) &address, &len); + ok(fdRead != INVALID_SOCKET, "expected a valid socket\n"); + + /* Test client side connection attempt notifications */ + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN | POLLOUT); + POLL_SET(fdRead, POLLIN | POLLOUT); + POLL_SET(fdWrite, POLLIN | POLLOUT); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 2, "expected 2, got %d\n", ret); + ok(POLL_ISSET(fdWrite, POLLWRNORM), "fdWrite socket events incorrect\n"); + ok(POLL_ISSET(fdRead, POLLWRNORM), "fdRead socket events incorrect\n"); + len = sizeof(id); + id = 0xdeadbeef; + ok(!getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char*)&id, &len), + "getsockopt failed with %d\n",WSAGetLastError()); + ok(id == 0, "expected 0, got %d\n", id); + + /* Test data receiving notifications */ + ret = send(fdWrite, "1234", 4, 0); + ok(ret == 4, "expected 4, got %d\n", ret); + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN | POLLOUT); + POLL_SET(fdRead, POLLIN); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdRead, POLLRDNORM), "fdRead socket events incorrect\n"); + ret = recv(fdRead, tmp_buf, sizeof(tmp_buf), 0); + ok(ret == 4, "expected 4, got %d\n", ret); + ok(!strcmp(tmp_buf, "1234"), "data received differs from sent\n"); + + /* Test OOB data notifications */ + ret = send(fdWrite, "A", 1, MSG_OOB); + ok(ret == 1, "expected 1, got %d\n", ret); + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN | POLLOUT); + POLL_SET(fdRead, POLLIN); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdRead, POLLRDBAND), "fdRead socket events incorrect\n"); + tmp_buf[0] = 0xAF; + ret = recv(fdRead, tmp_buf, sizeof(tmp_buf), MSG_OOB); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(tmp_buf[0] == 'A', "expected 'A', got 0x%02X\n", tmp_buf[0]); + + /* If the socket is OOBINLINED the notification is like normal data */ + ret = 1; + ret = setsockopt(fdRead, SOL_SOCKET, SO_OOBINLINE, (char*) &ret, sizeof(ret)); + ok(ret == 0, "expected 0, got %d\n", ret); + ret = send(fdWrite, "A", 1, MSG_OOB); + ok(ret == 1, "expected 1, got %d\n", ret); + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN | POLLOUT); + POLL_SET(fdRead, POLLIN | POLLOUT); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + tmp_buf[0] = 0xAF; + SetLastError(0xdeadbeef); + ret = recv(fdRead, tmp_buf, sizeof(tmp_buf), MSG_OOB); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ok(GetLastError() == WSAEINVAL, "expected 10022, got %d\n", GetLastError()); + ret = recv(fdRead, tmp_buf, sizeof(tmp_buf), 0); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(tmp_buf[0] == 'A', "expected 'A', got 0x%02X\n", tmp_buf[0]); + + /* Test connection closed notifications */ + ret = closesocket(fdRead); + ok(ret == 0, "expected 0, got %d\n", ret); + POLL_CLEAR(); + POLL_SET(fdListen, POLLIN | POLLOUT); + POLL_SET(fdWrite, POLLIN); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdWrite, POLLHUP), "fdWrite socket events incorrect\n"); + ret = recv(fdWrite, tmp_buf, sizeof(tmp_buf), 0); + ok(ret == 0, "expected 0, got %d\n", ret); + + /* When a connection is attempted to a non-listening socket due to a bug + * in the MS code it will never be notified. This is a long standing issue + * that will never be fixed for compatibility reasons so we have to deal + * with it manually. */ + ret = closesocket(fdWrite); + ok(ret == 0, "expected 0, got %d\n", ret); + ret = closesocket(fdListen); + ok(ret == 0, "expected 0, got %d\n", ret); + len = sizeof(address); + fdWrite = setup_connector_socket(&address, len, TRUE); + POLL_CLEAR(); + POLL_SET(fdWrite, POLLIN | POLLOUT); + poll_timeout = 2000; + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 0, "expected 0, got %d\n", ret); + len = sizeof(id); + id = 0xdeadbeef; + ok(!getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char*)&id, &len), + "getsockopt failed with %d\n", WSAGetLastError()); + ok(id == WSAECONNREFUSED, "expected 10061, got %d\n", id); + closesocket(fdWrite); + + /* Try poll() on a closed socket after connection */ + ok(!tcp_socketpair(&fdRead, &fdWrite), "creating socket pair failed\n"); + closesocket(fdRead); + POLL_CLEAR(); + POLL_SET(fdWrite, POLLIN | POLLOUT); + POLL_SET(fdRead, POLLIN | POLLOUT); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdRead, POLLNVAL), "fdRead socket events incorrect\n"); + POLL_CLEAR(); + POLL_SET(fdWrite, POLLIN | POLLOUT); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdWrite, POLLWRNORM | POLLHUP) || broken(POLL_ISSET(fdWrite, POLLWRNORM)) /* <= 2008 */, + "fdWrite socket events incorrect\n"); + closesocket(fdWrite); + + /* Close the socket currently being polled in a thread */ + ok(!tcp_socketpair(&fdRead, &fdWrite), "creating socket pair failed\n"); + thread_handle = CreateThread(NULL, 0, SelectCloseThread, &fdWrite, 0, &id); + ok(thread_handle != NULL, "CreateThread failed unexpectedly: %d\n", GetLastError()); + POLL_CLEAR(); + POLL_SET(fdWrite, POLLIN | POLLOUT); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdWrite, POLLWRNORM), "fdWrite socket events incorrect\n"); + WaitForSingleObject (thread_handle, 1000); + closesocket(fdRead); + /* test again with less flags - behavior changes */ + ok(!tcp_socketpair(&fdRead, &fdWrite), "creating socket pair failed\n"); + thread_handle = CreateThread(NULL, 0, SelectCloseThread, &fdWrite, 0, &id); + ok(thread_handle != NULL, "CreateThread failed unexpectedly: %d\n", GetLastError()); + POLL_CLEAR(); + POLL_SET(fdWrite, POLLIN); + ret = pWSAPoll(fds, ix, poll_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(POLL_ISSET(fdWrite, POLLNVAL), "fdWrite socket events incorrect\n"); + WaitForSingleObject (thread_handle, 1000); + closesocket(fdRead); +} +#undef POLL_SET +#undef POLL_ISSET +#undef POLL_CLEAR + static void test_GetAddrInfoW(void) { static const WCHAR port[] = {'8','0',0}; @@ -9195,6 +9416,7 @@ START_TEST( sock ) test_WSASendMsg(); test_WSASendTo(); test_WSARecv(); + test_WSAPoll(); test_events(0); test_events(1); -- 2.11.4.GIT