From a6161c8c116f555d0aec472638cb040fdac0b4e3 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Mon, 18 Jul 2016 10:44:58 +0000 Subject: [PATCH] [WS2_32_WINETEST] Sync with Wine Staging 1.9.14. Made possible thanks to Peter Hater's changes. CORE-11368 ROSTESTS-233 svn path=/trunk/; revision=71961 --- rostests/winetests/ws2_32/ros_diff.patch | 160 ++ rostests/winetests/ws2_32/sock.c | 2291 ++++++++++++++++++++-- 2 files changed, 2336 insertions(+), 115 deletions(-) create mode 100644 rostests/winetests/ws2_32/ros_diff.patch diff --git a/rostests/winetests/ws2_32/ros_diff.patch b/rostests/winetests/ws2_32/ros_diff.patch new file mode 100644 index 00000000000..ae47e44dd41 --- /dev/null +++ b/rostests/winetests/ws2_32/ros_diff.patch @@ -0,0 +1,160 @@ +diff -pudN --strip-trailing-cr e:\wine\dlls\ws2_32\tests/sock.c e:\reactos\modules\rostests\winetests\ws2_32/sock.c +--- e:\wine\dlls\ws2_32\tests/sock.c 2016-07-11 10:09:27 +0100 ++++ e:\reactos\modules\rostests\winetests\ws2_32/sock.c 2016-07-18 11:38:16 +0100 +@@ -3746,6 +3752,7 @@ static void test_select(void) + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + ++#if ROSTESTS_233_IS_FIXED + while(1) { + FD_ZERO(&writefds); + FD_SET(fdWrite, &writefds); +@@ -3753,6 +3760,8 @@ static void test_select(void) + if(!ret) break; + ok(send(fdWrite, tmp_buf, sizeof(tmp_buf), 0) > 0, "failed to send data\n"); + } ++#endif /* ROSTESTS_233_IS_FIXED */ ++ + FD_ZERO(&readfds); + FD_SET(fdWrite, &readfds); + FD_SET(fdRead, &readfds); +@@ -3925,6 +3934,8 @@ todo_wine + ok(exceptfds.fd_count == 2, "expected 2, got %d\n", exceptfds.fd_count); + closesocket(fdWrite); + ++#if ROSTESTS_233_IS_FIXED ++ + /* Close the socket currently being selected in a thread - bug 38399 */ + ok(!tcp_socketpair(&fdRead, &fdWrite), "creating socket pair failed\n"); + thread_handle = CreateThread(NULL, 0, SelectCloseThread, &fdWrite, 0, &id); +@@ -3951,6 +3962,8 @@ todo_wine + WaitForSingleObject (thread_handle, 1000); + closesocket(fdRead); + ++#endif /* ROSTESTS_233_IS_FIXED */ ++ + /* test UDP behavior of unbound sockets */ + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 250000; +@@ -4467,10 +4480,12 @@ static void test_dns(void) + "hostent->h_addr_list[0] should be in %p, it is in %p\n", addr.mem, h->h_addr_list[0]); + } + ++#ifndef __REACTOS__ + /* Our winsock headers don't define gethostname because it conflicts with the + * definition in unistd.h. Define it here to get rid of the warning. */ + + int WINAPI gethostname(char *name, int namelen); ++#endif + + static void test_gethostbyname(void) + { +@@ -4489,17 +4504,24 @@ static void test_gethostbyname(void) + + he = gethostbyname(name); + ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); +- addr_list = (struct in_addr **)he->h_addr_list; +- strcpy(first_ip, inet_ntoa(*addr_list[0])); +- +- trace("List of local IPs:\n"); +- for(count = 0; addr_list[count] != NULL; count++) ++#ifdef __REACTOS__ /* ROSTESTS-233 */ ++ if (he != NULL) + { +- char *ip = inet_ntoa(*addr_list[count]); +- if (!strcmp(ip, "127.0.0.1")) +- local_ip = TRUE; +- trace("%s\n", ip); ++#endif ++ addr_list = (struct in_addr **)he->h_addr_list; ++ strcpy(first_ip, inet_ntoa(*addr_list[0])); ++ ++ trace("List of local IPs:\n"); ++ for(count = 0; addr_list[count] != NULL; count++) ++ { ++ char *ip = inet_ntoa(*addr_list[count]); ++ if (!strcmp(ip, "127.0.0.1")) ++ local_ip = TRUE; ++ trace("%s\n", ip); ++ } ++#ifdef __REACTOS__ /* ROSTESTS-233 */ + } ++#endif + + if (local_ip) + { +@@ -6839,7 +6861,7 @@ static void test_GetAddrInfoW(void) + + ret = pGetAddrInfoW(empty, NULL, NULL, &result2); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); +- ok(result != NULL, "GetAddrInfoW failed\n"); ++ ok(result2 != NULL, "GetAddrInfoW failed\n"); + compare_addrinfow(result, result2); + pFreeAddrInfoW(result); + pFreeAddrInfoW(result2); +@@ -6850,7 +6872,7 @@ static void test_GetAddrInfoW(void) + + ret = pGetAddrInfoW(empty, empty, NULL, &result2); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); +- ok(result != NULL, "GetAddrInfoW failed\n"); ++ ok(result2 != NULL, "GetAddrInfoW failed\n"); + compare_addrinfow(result, result2); + pFreeAddrInfoW(result); + pFreeAddrInfoW(result2); +@@ -7025,22 +7047,22 @@ static void test_getaddrinfo(void) + * as if requesting with an empty host name. */ + ret = pgetaddrinfo(name, NULL, NULL, &result); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); +- ok(result != NULL, "GetAddrInfoW failed\n"); ++ ok(result != NULL, "getaddrinfo failed\n"); + + ret = pgetaddrinfo("", NULL, NULL, &result2); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); +- ok(result != NULL, "GetAddrInfoW failed\n"); ++ ok(result2 != NULL, "getaddrinfo failed\n"); + compare_addrinfo(result, result2); + pfreeaddrinfo(result); + pfreeaddrinfo(result2); + + ret = pgetaddrinfo(name, "", NULL, &result); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); +- ok(result != NULL, "GetAddrInfoW failed\n"); ++ ok(result != NULL, "getaddrinfo failed\n"); + + ret = pgetaddrinfo("", "", NULL, &result2); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); +- ok(result != NULL, "GetAddrInfoW failed\n"); ++ ok(result2 != NULL, "getaddrinfo failed\n"); + compare_addrinfo(result, result2); + pfreeaddrinfo(result); + pfreeaddrinfo(result2); +@@ -9539,6 +9561,14 @@ todo_wine + todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + ++#ifdef __REACTOS__ /* ROSTESTS-233 */ ++ if (!blen) ++ { ++ skip("Failed to get length needed for name space providers.\n"); ++ return; ++ } ++#endif ++ + name = HeapAlloc(GetProcessHeap(), 0, blen); + if (!name) + { +@@ -9616,6 +9646,14 @@ todo_wine + todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + ++#ifdef __REACTOS__ /* ROSTESTS-233 */ ++ if (!blen) ++ { ++ skip("Failed to get length needed for name space providers.\n"); ++ return; ++ } ++#endif ++ + name = HeapAlloc(GetProcessHeap(), 0, blen); + if (!name) + { diff --git a/rostests/winetests/ws2_32/sock.c b/rostests/winetests/ws2_32/sock.c index aa47640a13f..a5a279bd946 100644 --- a/rostests/winetests/ws2_32/sock.c +++ b/rostests/winetests/ws2_32/sock.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -73,9 +74,18 @@ static int (WINAPI *pgetaddrinfo)(LPCSTR,LPCSTR,const struct addrinfo *,struct static void (WINAPI *pFreeAddrInfoW)(PADDRINFOW); static int (WINAPI *pGetAddrInfoW)(LPCWSTR,LPCWSTR,const ADDRINFOW *,PADDRINFOW *); static PCSTR (WINAPI *pInetNtop)(INT,LPVOID,LPSTR,ULONG); +static int (WINAPI *pInetPtonA)(INT,LPCSTR,LPVOID); +static int (WINAPI *pInetPtonW)(INT,LPWSTR,LPVOID); static int (WINAPI *pWSALookupServiceBeginW)(LPWSAQUERYSETW,DWORD,LPHANDLE); 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); + +/* Function pointers from iphlpapi */ +static DWORD (WINAPI *pGetAdaptersInfo)(PIP_ADAPTER_INFO,PULONG); +static DWORD (WINAPI *pGetIpForwardTable)(PMIB_IPFORWARDTABLE,PULONG,BOOL); /**************** Structs and typedefs ***************/ @@ -166,24 +176,32 @@ static const struct addr_hint_tests } hinttests[] = { {AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0 }, {AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP, 0 }, + {AF_UNSPEC, SOCK_STREAM, IPPROTO_IPV6,0 }, {AF_UNSPEC, SOCK_DGRAM, IPPROTO_TCP, 0 }, {AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, 0 }, + {AF_UNSPEC, SOCK_DGRAM, IPPROTO_IPV6,0 }, {AF_INET, SOCK_STREAM, IPPROTO_TCP, 0 }, {AF_INET, SOCK_STREAM, IPPROTO_UDP, 0 }, + {AF_INET, SOCK_STREAM, IPPROTO_IPV6,0 }, {AF_INET, SOCK_DGRAM, IPPROTO_TCP, 0 }, {AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0 }, + {AF_INET, SOCK_DGRAM, IPPROTO_IPV6,0 }, {AF_UNSPEC, 0, IPPROTO_TCP, 0 }, {AF_UNSPEC, 0, IPPROTO_UDP, 0 }, + {AF_UNSPEC, 0, IPPROTO_IPV6,0 }, {AF_UNSPEC, SOCK_STREAM, 0, 0 }, {AF_UNSPEC, SOCK_DGRAM, 0, 0 }, {AF_INET, 0, IPPROTO_TCP, 0 }, {AF_INET, 0, IPPROTO_UDP, 0 }, + {AF_INET, 0, IPPROTO_IPV6,0 }, {AF_INET, SOCK_STREAM, 0, 0 }, {AF_INET, SOCK_DGRAM, 0, 0 }, {AF_UNSPEC, 999, IPPROTO_TCP, WSAESOCKTNOSUPPORT }, {AF_UNSPEC, 999, IPPROTO_UDP, WSAESOCKTNOSUPPORT }, + {AF_UNSPEC, 999, IPPROTO_IPV6,WSAESOCKTNOSUPPORT }, {AF_INET, 999, IPPROTO_TCP, WSAESOCKTNOSUPPORT }, {AF_INET, 999, IPPROTO_UDP, WSAESOCKTNOSUPPORT }, + {AF_INET, 999, IPPROTO_IPV6,WSAESOCKTNOSUPPORT }, {AF_UNSPEC, SOCK_STREAM, 999, 0 }, {AF_UNSPEC, SOCK_STREAM, 999, 0 }, {AF_INET, SOCK_DGRAM, 999, 0 }, @@ -201,6 +219,9 @@ static int client_id; /**************** General utility functions ***************/ +static SOCKET setup_server_socket(struct sockaddr_in *addr, int *len); +static SOCKET setup_connector_socket(struct sockaddr_in *addr, int len, BOOL nonblock); + static int tcp_socketpair(SOCKET *src, SOCKET *dst) { SOCKET server = INVALID_SOCKET; @@ -211,11 +232,11 @@ static int tcp_socketpair(SOCKET *src, SOCKET *dst) *src = INVALID_SOCKET; *dst = INVALID_SOCKET; - *src = socket(AF_INET, SOCK_STREAM, 0); + *src = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (*src == INVALID_SOCKET) goto end; - server = socket(AF_INET, SOCK_STREAM, 0); + server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == INVALID_SOCKET) goto end; @@ -303,32 +324,41 @@ static void read_zero_bytes ( SOCKET s ) ok ( n <= 0, "garbage data received: %d bytes\n", n ); } -static int do_synchronous_send ( SOCKET s, char *buf, int buflen, int sendlen, int flags ) +static int do_synchronous_send ( SOCKET s, char *buf, int buflen, int flags, int sendlen ) { char* last = buf + buflen, *p; int n = 1; - for ( p = buf; n > 0 && p < last; p += n ) + for ( p = buf; n > 0 && p < last; ) + { n = send ( s, p, min ( sendlen, last - p ), flags ); + if (n > 0) p += n; + } wsa_ok ( n, 0 <=, "do_synchronous_send (%x): error %d\n" ); return p - buf; } -static int do_synchronous_recv ( SOCKET s, char *buf, int buflen, int recvlen ) +static int do_synchronous_recv ( SOCKET s, char *buf, int buflen, int flags, int recvlen ) { char* last = buf + buflen, *p; int n = 1; - for ( p = buf; n > 0 && p < last; p += n ) - n = recv ( s, p, min ( recvlen, last - p ), 0 ); + for ( p = buf; n > 0 && p < last; ) + { + n = recv ( s, p, min ( recvlen, last - p ), flags ); + if (n > 0) p += n; + } wsa_ok ( n, 0 <=, "do_synchronous_recv (%x): error %d:\n" ); return p - buf; } -static int do_synchronous_recvfrom ( SOCKET s, char *buf, int buflen,int flags,struct sockaddr *from, int *fromlen, int recvlen ) +static int do_synchronous_recvfrom ( SOCKET s, char *buf, int buflen, int flags, struct sockaddr *from, int *fromlen, int recvlen ) { char* last = buf + buflen, *p; int n = 1; - for ( p = buf; n > 0 && p < last; p += n ) - n = recvfrom ( s, p, min ( recvlen, last - p ), 0, from, fromlen ); + for ( p = buf; n > 0 && p < last; ) + { + n = recvfrom ( s, p, min ( recvlen, last - p ), flags, from, fromlen ); + if (n > 0) p += n; + } wsa_ok ( n, 0 <=, "do_synchronous_recv (%x): error %d:\n" ); return p - buf; } @@ -540,14 +570,14 @@ static VOID WINAPI simple_server ( server_params *par ) "simple_server (%x): strange peer address\n", id ); /* Receive data & check it */ - n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen ); + n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, 0, par->buflen ); ok ( n_recvd == n_expected, "simple_server (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); pos = test_buffer ( mem->sock[0].buf, gen->chunk_size, gen->n_chunks ); ok ( pos == -1, "simple_server (%x): test pattern error: %d\n", id, pos); /* Echo data back */ - n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen, 0 ); + n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, 0, par->buflen ); ok ( n_sent == n_expected, "simple_server (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); @@ -599,32 +629,32 @@ static VOID WINAPI oob_server ( server_params *par ) ok ( atmark == 1, "oob_server (%x): unexpectedly at the OOB mark: %i\n", id, atmark ); /* Receive normal data */ - n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen ); + n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, 0, par->buflen ); ok ( n_recvd == n_expected, "oob_server (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); pos = test_buffer ( mem->sock[0].buf, gen->chunk_size, gen->n_chunks ); ok ( pos == -1, "oob_server (%x): test pattern error: %d\n", id, pos); - /* Echo data back */ - n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen, 0 ); - ok ( n_sent == n_expected, - "oob_server (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); - /* check atmark state */ ioctlsocket ( mem->sock[0].s, SIOCATMARK, &atmark ); ok ( atmark == 1, "oob_server (%x): unexpectedly at the OOB mark: %i\n", id, atmark ); - /* Receive a part of the out-of-band data and check atmark state */ - n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, 8, par->buflen ); + /* Echo data back */ + n_sent = do_synchronous_send ( mem->sock[0].s, mem->sock[0].buf, n_expected, 0, par->buflen ); + ok ( n_sent == n_expected, + "oob_server (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); + + /* Receive a part of the out-of-band data and print atmark state */ + n_recvd = do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, 8, 0, par->buflen ); ok ( n_recvd == 8, "oob_server (%x): received less data than expected: %d of %d\n", id, n_recvd, 8 ); n_expected -= 8; ioctlsocket ( mem->sock[0].s, SIOCATMARK, &atmark ); - todo_wine ok ( atmark == 0, "oob_server (%x): not at the OOB mark: %i\n", id, atmark ); + trace( "oob_server (%x): %s the OOB mark: %i\n", id, atmark == 1 ? "not at" : "at", atmark ); /* Receive the rest of the out-of-band data and check atmark state */ - do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, par->buflen ); + do_synchronous_recv ( mem->sock[0].s, mem->sock[0].buf, n_expected, 0, par->buflen ); ioctlsocket ( mem->sock[0].s, SIOCATMARK, &atmark ); todo_wine ok ( atmark == 0, "oob_server (%x): not at the OOB mark: %i\n", id, atmark ); @@ -797,7 +827,7 @@ static VOID WINAPI simple_client ( client_params *par ) trace ( "simple_client (%x) connected\n", id ); /* send data to server */ - n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen, 0 ); + n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, 0, par->buflen ); ok ( n_sent == n_expected, "simple_client (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); @@ -805,7 +835,7 @@ static VOID WINAPI simple_client ( client_params *par ) wsa_ok ( shutdown ( mem->s, SD_SEND ), 0 ==, "simple_client (%x): shutdown failed: %d\n" ); /* Receive data echoed back & check it */ - n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, par->buflen ); + n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, 0, par->buflen ); ok ( n_recvd == n_expected, "simple_client (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); @@ -847,19 +877,19 @@ static VOID WINAPI oob_client ( client_params *par ) trace ( "oob_client (%x) connected\n", id ); /* send data to server */ - n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen, 0 ); + n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, 0, par->buflen ); ok ( n_sent == n_expected, "oob_client (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); /* Receive data echoed back & check it */ - n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, par->buflen ); + n_recvd = do_synchronous_recv ( mem->s, mem->recv_buf, n_expected, 0, par->buflen ); ok ( n_recvd == n_expected, "simple_client (%x): received less data than expected: %d of %d\n", id, n_recvd, n_expected ); pos = test_buffer ( mem->recv_buf, gen->chunk_size, gen->n_chunks ); ok ( pos == -1, "simple_client (%x): test pattern error: %d\n", id, pos); /* send out-of-band data to server */ - n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen, MSG_OOB ); + n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, MSG_OOB, par->buflen ); ok ( n_sent == n_expected, "oob_client (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); @@ -902,7 +932,7 @@ static VOID WINAPI simple_mixed_client ( client_params *par ) trace ( "simple_client (%x) connected\n", id ); /* send data to server */ - n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, par->buflen, 0 ); + n_sent = do_synchronous_send ( mem->s, mem->send_buf, n_expected, 0, par->buflen ); ok ( n_sent == n_expected, "simple_client (%x): sent less data than expected: %d of %d\n", id, n_sent, n_expected ); @@ -1090,9 +1120,13 @@ static void test_WithWSAStartup(void) { WSADATA data; WORD version = MAKEWORD( 2, 2 ); - INT res; + INT res, socks, i, j; + SOCKET sock; LPVOID ptr; - SOCKET src, dst; + struct + { + SOCKET src, dst, dup_src, dup_dst; + } pairs[128]; DWORD error; res = WSAStartup( version, &data ); @@ -1101,9 +1135,26 @@ static void test_WithWSAStartup(void) ptr = gethostbyname("localhost"); ok(ptr != NULL, "gethostbyname() failed unexpectedly: %d\n", WSAGetLastError()); - ok(!tcp_socketpair(&src, &dst), "creating socket pair failed\n"); + /* Alloc some sockets to check if they are destroyed on WSACleanup */ + for (socks = 0; socks < sizeof(pairs) / sizeof(pairs[0]); socks++) + { + WSAPROTOCOL_INFOA info; + if (tcp_socketpair(&pairs[socks].src, &pairs[socks].dst)) break; + + memset(&info, 0, sizeof(info)); + ok(!WSADuplicateSocketA(pairs[socks].src, GetCurrentProcessId(), &info), + "WSADuplicateSocketA should have worked\n"); + pairs[socks].dup_src = WSASocketA(0, 0, 0, &info, 0, 0); + ok(pairs[socks].dup_src != SOCKET_ERROR, "expected != -1\n"); + + memset(&info, 0, sizeof(info)); + ok(!WSADuplicateSocketA(pairs[socks].dst, GetCurrentProcessId(), &info), + "WSADuplicateSocketA should have worked\n"); + pairs[socks].dup_dst = WSASocketA(0, 0, 0, &info, 0, 0); + ok(pairs[socks].dup_dst != SOCKET_ERROR, "expected != -1\n"); + } - res = send(src, "TEST", 4, 0); + res = send(pairs[0].src, "TEST", 4, 0); ok(res == 4, "send failed with error %d\n", WSAGetLastError()); WSACleanup(); @@ -1112,24 +1163,58 @@ static void test_WithWSAStartup(void) ok(res == 0, "WSAStartup() failed unexpectedly: %d\n", res); /* show that sockets are destroyed automatically after WSACleanup */ - todo_wine { SetLastError(0xdeadbeef); - res = send(src, "TEST", 4, 0); + res = send(pairs[0].src, "TEST", 4, 0); error = WSAGetLastError(); ok(res == SOCKET_ERROR, "send should have failed\n"); - ok(error == WSAENOTSOCK, "expected 10038, got %d\n", error); + todo_wine ok(error == WSAENOTSOCK, "expected 10038, got %d\n", error); SetLastError(0xdeadbeef); - res = closesocket(dst); + res = send(pairs[0].dst, "TEST", 4, 0); error = WSAGetLastError(); - ok(res == SOCKET_ERROR, "closesocket should have failed\n"); - ok(error == WSAENOTSOCK, "expected 10038, got %d\n", error); + ok(res == SOCKET_ERROR, "send should have failed\n"); + todo_wine ok(error == WSAENOTSOCK, "expected 10038, got %d\n", error); + + /* Check that all sockets were destroyed */ + for (i = 0; i < socks; i++) + { + for (j = 0; j < 4; j++) + { + struct sockaddr_in saddr; + int size = sizeof(saddr); + switch(j) + { + case 0: sock = pairs[i].src; break; + case 1: sock = pairs[i].dup_src; break; + case 2: sock = pairs[i].dst; break; + case 3: sock = pairs[i].dup_dst; break; + } + + SetLastError(0xdeadbeef); + res = getsockname(sock, (struct sockaddr *)&saddr, &size); + error = WSAGetLastError(); + ok(res == SOCKET_ERROR, "Test[%d]: getsockname should have failed\n", i); + todo_wine ok(error == WSAENOTSOCK, "Test[%d]: expected 10038, got %d\n", i, error); + } } - closesocket(src); - closesocket(dst); + /* While wine is not fixed, close all sockets manually */ + for (i = 0; i < socks; i++) + { + closesocket(pairs[i].src); + closesocket(pairs[i].dst); + closesocket(pairs[i].dup_src); + closesocket(pairs[i].dup_dst); + } - WSACleanup(); + res = WSACleanup(); + ok(res == 0, "expected 0, got %d\n", res); + WSASetLastError(0xdeadbeef); + res = WSACleanup(); + error = WSAGetLastError(); + ok ( (res == SOCKET_ERROR && error == WSANOTINITIALISED) || + broken(res == 0), /* WinME */ + "WSACleanup returned %d WSAGetLastError is %d\n", res, error); } /**************** Main program utility functions ***************/ @@ -1138,16 +1223,28 @@ static void Init (void) { WORD ver = MAKEWORD (2, 2); WSADATA data; - HMODULE hws2_32 = GetModuleHandleA("ws2_32.dll"); + HMODULE hws2_32 = GetModuleHandleA("ws2_32.dll"), hiphlpapi; pfreeaddrinfo = (void *)GetProcAddress(hws2_32, "freeaddrinfo"); pgetaddrinfo = (void *)GetProcAddress(hws2_32, "getaddrinfo"); pFreeAddrInfoW = (void *)GetProcAddress(hws2_32, "FreeAddrInfoW"); pGetAddrInfoW = (void *)GetProcAddress(hws2_32, "GetAddrInfoW"); pInetNtop = (void *)GetProcAddress(hws2_32, "inet_ntop"); + pInetPtonA = (void *)GetProcAddress(hws2_32, "inet_pton"); + pInetPtonW = (void *)GetProcAddress(hws2_32, "InetPtonW"); pWSALookupServiceBeginW = (void *)GetProcAddress(hws2_32, "WSALookupServiceBeginW"); pWSALookupServiceEnd = (void *)GetProcAddress(hws2_32, "WSALookupServiceEnd"); pWSALookupServiceNextW = (void *)GetProcAddress(hws2_32, "WSALookupServiceNextW"); + pWSAEnumNameSpaceProvidersA = (void *)GetProcAddress(hws2_32, "WSAEnumNameSpaceProvidersA"); + pWSAEnumNameSpaceProvidersW = (void *)GetProcAddress(hws2_32, "WSAEnumNameSpaceProvidersW"); + pWSAPoll = (void *)GetProcAddress(hws2_32, "WSAPoll"); + + hiphlpapi = LoadLibraryA("iphlpapi.dll"); + if (hiphlpapi) + { + pGetIpForwardTable = (void *)GetProcAddress(hiphlpapi, "GetIpForwardTable"); + pGetAdaptersInfo = (void *)GetProcAddress(hiphlpapi, "GetAdaptersInfo"); + } ok ( WSAStartup ( ver, &data ) == 0, "WSAStartup failed\n" ); tls = TlsAlloc(); @@ -1160,11 +1257,6 @@ static void Exit (void) ret = WSACleanup(); err = WSAGetLastError(); ok ( ret == 0, "WSACleanup failed ret = %d GetLastError is %d\n", ret, err); - ret = WSACleanup(); - err = WSAGetLastError(); - ok ( (ret == SOCKET_ERROR && err == WSANOTINITIALISED) || - broken(ret == 0), /* WinME */ - "WSACleanup returned %d GetLastError is %d\n", ret, err); } static void StartServer (LPTHREAD_START_ROUTINE routine, @@ -1239,7 +1331,7 @@ static const LINGER linger_testvals[] = { static void test_set_getsockopt(void) { - SOCKET s; + SOCKET s, s2; int i, err, lasterr; int timeout; LINGER lingval; @@ -1247,6 +1339,7 @@ static void test_set_getsockopt(void) WSAPROTOCOL_INFOA infoA; WSAPROTOCOL_INFOW infoW; char providername[WSAPROTOCOL_LEN + 1]; + DWORD value; struct _prottest { int family, type, proto; @@ -1256,6 +1349,11 @@ static void test_set_getsockopt(void) {AF_INET6, SOCK_STREAM, IPPROTO_TCP}, {AF_INET6, SOCK_DGRAM, IPPROTO_UDP} }; + union _csspace + { + CSADDR_INFO cs; + char space[128]; + } csinfoA, csinfoB; s = socket(AF_INET, SOCK_STREAM, 0); ok(s!=INVALID_SOCKET, "socket() failed error: %d\n", WSAGetLastError()); @@ -1285,6 +1383,27 @@ static void test_set_getsockopt(void) err = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, &size); ok( !err, "get/setsockopt(SO_SNDTIMEO) failed error: %d\n", WSAGetLastError()); ok( timeout == SOCKTIMEOUT2, "getsockopt(SO_SNDTIMEO) returned wrong value %d\n", timeout); + + /* SO_SNDBUF */ + value = 4096; + size = sizeof(value); + err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&value, size); + ok( !err, "setsockopt(SO_SNDBUF) failed error: %u\n", WSAGetLastError() ); + value = 0xdeadbeef; + err = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&value, &size); + ok( !err, "getsockopt(SO_SNDBUF) failed error: %u\n", WSAGetLastError() ); + ok( value == 4096, "expected 4096, got %u\n", value ); + + /* SO_RCVBUF */ + value = 4096; + size = sizeof(value); + err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&value, size); + ok( !err, "setsockopt(SO_RCVBUF) failed error: %u\n", WSAGetLastError() ); + value = 0xdeadbeef; + err = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&value, &size); + ok( !err, "getsockopt(SO_RCVBUF) failed error: %u\n", WSAGetLastError() ); + ok( value == 4096, "expected 4096, got %u\n", value ); + /* SO_LINGER */ for( i = 0; i < sizeof(linger_testvals)/sizeof(LINGER);i++) { size = sizeof(lingval); @@ -1372,6 +1491,40 @@ todo_wine err, WSAGetLastError()); closesocket(s); + /* Test with the closed socket */ + SetLastError(0xdeadbeef); + size = sizeof(i); + i = 1234; + err = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &i, &size); +todo_wine + ok( (err == SOCKET_ERROR) && (WSAGetLastError() == WSAENOTSOCK), + "got %d with %d (expected SOCKET_ERROR with WSAENOTSOCK)\n", + err, WSAGetLastError()); + ok (i == 1234, "expected 1234, got %d\n", i); + + /* Test WS_IP_MULTICAST_TTL with 8, 16, 24 and 32 bits values */ + s = socket(AF_INET, SOCK_DGRAM, 0); + ok(s != INVALID_SOCKET, "Failed to create socket\n"); + size = sizeof(i); + i = 0x0000000a; + err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &i, size); + if (!err) + { + for (i = 0; i < 4; i++) + { + int k, j; + const int tests[] = {0xffffff0a, 0xffff000b, 0xff00000c, 0x0000000d}; + err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &tests[i], i + 1); + ok(!err, "Test [%d] Expected 0, got %d\n", i, err); + err = getsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &k, &size); + ok(!err, "Test [%d] Expected 0, got %d\n", i, err); + j = i != 3 ? tests[i] & ((1 << (i + 1) * 8) - 1) : tests[i]; + ok(k == j, "Test [%d] Expected 0x%x, got 0x%x\n", i, j, k); + } + } + else + win_skip("IP_MULTICAST_TTL is unsupported\n"); + closesocket(s); /* test SO_PROTOCOL_INFOA invalid parameters */ ok(getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_PROTOCOL_INFOA, NULL, NULL), @@ -1449,23 +1602,126 @@ todo_wine "SO_PROTOCOL_INFO[A/W] comparison failed\n"); /* Remove IF when WSAEnumProtocols support IPV6 data */ - if (prottest[i].family == AF_INET6) - { - todo_wine + todo_wine_if (prottest[i].family == AF_INET6) ok(infoA.iAddressFamily == prottest[i].family, "socket family invalid, expected %d received %d\n", prottest[i].family, infoA.iAddressFamily); - } - else - { - ok(infoA.iAddressFamily == prottest[i].family, "socket family invalid, expected %d received %d\n", - prottest[i].family, infoA.iAddressFamily); - } ok(infoA.iSocketType == prottest[i].type, "socket type invalid, expected %d received %d\n", + ok(infoA.iSocketType == prottest[i].type, "socket type invalid, expected %d received %d\n", prottest[i].type, infoA.iSocketType); ok(infoA.iProtocol == prottest[i].proto, "socket protocol invalid, expected %d received %d\n", prottest[i].proto, infoA.iProtocol); closesocket(s); } + + /* Test SO_BSP_STATE - Present only in >= Win 2008 */ + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(s != INVALID_SOCKET, "Failed to create socket\n"); + s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(s2 != INVALID_SOCKET, "Failed to create socket\n"); + + SetLastError(0xdeadbeef); + size = sizeof(csinfoA); + err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size); + if (!err) + { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + /* Socket is not bound, no information provided */ + ok(!csinfoA.cs.LocalAddr.iSockaddrLength, "Expected 0, got %d\n", csinfoA.cs.LocalAddr.iSockaddrLength); + ok(csinfoA.cs.LocalAddr.lpSockaddr == NULL, "Expected NULL, got %p\n", csinfoA.cs.LocalAddr.lpSockaddr); + /* Socket is not connected, no information provided */ + ok(!csinfoA.cs.RemoteAddr.iSockaddrLength, "Expected 0, got %d\n", csinfoA.cs.LocalAddr.iSockaddrLength); + ok(csinfoA.cs.RemoteAddr.lpSockaddr == NULL, "Expected NULL, got %p\n", csinfoA.cs.LocalAddr.lpSockaddr); + + err = bind(s, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(!err, "Expected 0, got %d\n", err); + size = sizeof(csinfoA); + err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size); + ok(!err, "Expected 0, got %d\n", err); + + /* Socket is bound */ + ok(csinfoA.cs.LocalAddr.iSockaddrLength, "Expected non-zero\n"); + ok(csinfoA.cs.LocalAddr.lpSockaddr != NULL, "Expected non-null\n"); + /* Socket is not connected, no information provided */ + ok(!csinfoA.cs.RemoteAddr.iSockaddrLength, "Expected 0, got %d\n", csinfoA.cs.LocalAddr.iSockaddrLength); + ok(csinfoA.cs.RemoteAddr.lpSockaddr == NULL, "Expected NULL, got %p\n", csinfoA.cs.LocalAddr.lpSockaddr); + + err = bind(s2, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(!err, "Expected 0, got %d\n", err); + err = getsockname(s2, (struct sockaddr *)&saddr, &size); + ok(!err, "Expected 0, got %d\n", err); + err = listen(s2, 1); + ok(!err, "Expected 0, got %d\n", err); + err = connect(s, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(!err, "Expected 0, got %d\n", err); + size = sizeof(saddr); + err = accept(s2, (struct sockaddr*)&saddr, &size); + ok(err != INVALID_SOCKET, "Failed to accept socket\n"); + closesocket(s2); + s2 = err; + + size = sizeof(csinfoA); + err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size); + ok(!err, "Expected 0, got %d\n", err); + err = getsockopt(s2, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoB, &size); + ok(!err, "Expected 0, got %d\n", err); + ok(size == sizeof(csinfoA), "Got %d\n", size); + size = sizeof(saddr); + ok(size == csinfoA.cs.LocalAddr.iSockaddrLength, "Expected %d, got %d\n", size, + csinfoA.cs.LocalAddr.iSockaddrLength); + ok(size == csinfoA.cs.RemoteAddr.iSockaddrLength, "Expected %d, got %d\n", size, + csinfoA.cs.RemoteAddr.iSockaddrLength); + ok(!memcmp(csinfoA.cs.LocalAddr.lpSockaddr, csinfoB.cs.RemoteAddr.lpSockaddr, size), + "Expected matching addresses\n"); + ok(!memcmp(csinfoB.cs.LocalAddr.lpSockaddr, csinfoA.cs.RemoteAddr.lpSockaddr, size), + "Expected matching addresses\n"); + ok(csinfoA.cs.iSocketType == SOCK_STREAM, "Wrong socket type\n"); + ok(csinfoB.cs.iSocketType == SOCK_STREAM, "Wrong socket type\n"); + ok(csinfoA.cs.iProtocol == IPPROTO_TCP, "Wrong socket protocol\n"); + ok(csinfoB.cs.iProtocol == IPPROTO_TCP, "Wrong socket protocol\n"); + + err = getpeername(s, (struct sockaddr *)&saddr, &size); + ok(!err, "Expected 0, got %d\n", err); + ok(!memcmp(&saddr, csinfoA.cs.RemoteAddr.lpSockaddr, size), "Expected matching addresses\n"); + ok(!memcmp(&saddr, csinfoB.cs.LocalAddr.lpSockaddr, size), "Expected matching addresses\n"); + err = getpeername(s2, (struct sockaddr *)&saddr, &size); + ok(!err, "Expected 0, got %d\n", err); + ok(!memcmp(&saddr, csinfoB.cs.RemoteAddr.lpSockaddr, size), "Expected matching addresses\n"); + ok(!memcmp(&saddr, csinfoA.cs.LocalAddr.lpSockaddr, size), "Expected matching addresses\n"); + err = getsockname(s, (struct sockaddr *)&saddr, &size); + ok(!err, "Expected 0, got %d\n", err); + ok(!memcmp(&saddr, csinfoA.cs.LocalAddr.lpSockaddr, size), "Expected matching addresses\n"); + ok(!memcmp(&saddr, csinfoB.cs.RemoteAddr.lpSockaddr, size), "Expected matching addresses\n"); + err = getsockname(s2, (struct sockaddr *)&saddr, &size); + ok(!err, "Expected 0, got %d\n", err); + ok(!memcmp(&saddr, csinfoB.cs.LocalAddr.lpSockaddr, size), "Expected matching addresses\n"); + ok(!memcmp(&saddr, csinfoA.cs.RemoteAddr.lpSockaddr, size), "Expected matching addresses\n"); + + SetLastError(0xdeadbeef); + size = sizeof(CSADDR_INFO); + err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size); + ok(err, "Expected non-zero\n"); + ok(size == sizeof(CSADDR_INFO), "Got %d\n", size); + ok(GetLastError() == WSAEFAULT, "Expected 10014, got %d\n", GetLastError()); + + /* At least for IPv4 the size is exactly 56 bytes */ + size = sizeof(*csinfoA.cs.LocalAddr.lpSockaddr) * 2 + sizeof(csinfoA.cs); + err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size); + ok(!err, "Expected 0, got %d\n", err); + size--; + SetLastError(0xdeadbeef); + err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size); + ok(err, "Expected non-zero\n"); + ok(GetLastError() == WSAEFAULT, "Expected 10014, got %d\n", GetLastError()); + } + else + ok(GetLastError() == WSAENOPROTOOPT, "Expected 10042, got %d\n", GetLastError()); + + closesocket(s); + closesocket(s2); } static void test_so_reuseaddr(void) @@ -1474,6 +1730,7 @@ static void test_so_reuseaddr(void) SOCKET s1,s2; unsigned int rc,reuse; int size; + DWORD err; saddr.sin_family = AF_INET; saddr.sin_port = htons(9375); @@ -1502,9 +1759,44 @@ static void test_so_reuseaddr(void) /* On Win2k3 and above, all SO_REUSEADDR seems to do is to allow binding to * a port immediately after closing another socket on that port, so * basically following the BSD socket semantics here. */ - closesocket(s1); rc = bind(s2, (struct sockaddr*)&saddr, sizeof(saddr)); - ok(rc==0, "bind() failed error: %d\n", WSAGetLastError()); + if(rc==0) + { + int s3=socket(AF_INET, SOCK_STREAM, 0), s4; + trace("<= Win XP behavior of SO_REUSEADDR\n"); + + /* If we could bind again in the same port this is Windows version <= XP. + * Lets test if we can really connect to one of them. */ + set_blocking(s1, FALSE); + set_blocking(s2, FALSE); + rc = listen(s1, 1); + ok(!rc, "listen() failed with error: %d\n", WSAGetLastError()); + rc = listen(s2, 1); + ok(!rc, "listen() failed with error: %d\n", WSAGetLastError()); + rc = connect(s3, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(!rc, "connecting to accepting socket failed %d\n", WSAGetLastError()); + + /* the delivery of the connection is random so we need to try on both sockets */ + size = sizeof(saddr); + s4 = accept(s1, (struct sockaddr*)&saddr, &size); + if(s4 == INVALID_SOCKET) + s4 = accept(s2, (struct sockaddr*)&saddr, &size); + ok(s4 != INVALID_SOCKET, "none of the listening sockets could get the connection\n"); + + closesocket(s1); + closesocket(s3); + closesocket(s4); + } + else + { + trace(">= Win 2003 behavior of SO_REUSEADDR\n"); + err = WSAGetLastError(); + ok(err==WSAEACCES, "expected 10013, got %d\n", err); + + closesocket(s1); + rc = bind(s2, (struct sockaddr*)&saddr, sizeof(saddr)); + ok(rc==0, "bind() failed error: %d\n", WSAGetLastError()); + } closesocket(s2); } @@ -1605,8 +1897,10 @@ static void test_ip_pktinfo(void) * Send a packet from the client to the server and test for specifying * a short control header. */ + SetLastError(0xdeadbeef); rc=sendto(s2, msg, sizeof(msg), 0, (struct sockaddr*)&s2addr, sizeof(s2addr)); ok(rc == sizeof(msg), "sendto() failed error: %d\n", WSAGetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); hdr.Control.len = 1; rc=pWSARecvMsg(s1, &hdr, &dwSize, NULL, NULL); err=WSAGetLastError(); @@ -1619,8 +1913,10 @@ static void test_ip_pktinfo(void) rc=pWSARecvMsg(s1, &hdr, NULL, &ov, NULL); err=WSAGetLastError(); ok(rc != 0 && err == WSA_IO_PENDING, "WSARecvMsg() failed error: %d\n", err); + SetLastError(0xdeadbeef); rc=sendto(s2, msg, sizeof(msg), 0, (struct sockaddr*)&s2addr, sizeof(s2addr)); ok(rc == sizeof(msg), "sendto() failed error: %d\n", WSAGetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); if (WaitForSingleObject(ov.hEvent, 100) != WAIT_OBJECT_0) { skip("Server side did not receive packet, some tests skipped.\n"); @@ -2237,6 +2533,7 @@ static void test_WSASocket(void) if (sock == INVALID_SOCKET) { err = WSAGetLastError(); + todo_wine_if (err == WSAEPROTONOSUPPORT) ok(err == WSAEAFNOSUPPORT || broken(err == WSAEPROTONOSUPPORT), "Expected 10047, received %d\n", err); skip("IPX is not supported\n"); } @@ -2359,7 +2656,7 @@ static void test_WSADuplicateSocket(void) closesocket(source); /* create a socket, bind it, duplicate it then send data on source and - * receve in the duplicated socket */ + * receive in the duplicated socket */ source = WSASocketA(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0); ok(source != INVALID_SOCKET, "WSASocketA should have succeeded\n"); @@ -2459,6 +2756,86 @@ static void test_WSADuplicateSocket(void) closesocket(source); } +static void test_WSAEnumNetworkEvents(void) +{ + SOCKET s, s2; + int sock_type[] = {SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM}, i, j, k, l; + struct sockaddr_in address; + HANDLE event; + WSANETWORKEVENTS net_events; + /* Windows 2000 Pro without SP installed (testbot) will crash if + * WSAEnumNetworkEvents have a NULL event, so skip this test in <= 2000 */ + DWORD ver = GetVersion() & 0xFFFF; + BOOL supports_null = ((ver & 0xFF) << 8 | (ver >> 8)) > 0x0500; + + memset(&address, 0, sizeof(address)); + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_family = AF_INET; + + /* This test follows the steps from bugs 10204 and 24946 */ + for (l = 0; l < 2; l++) + { + if (l == 1 && !supports_null && broken(1)) continue; + + for (i = 0; i < sizeof(sock_type) / sizeof(sock_type[0]); i++) + { + if (i == 2) + ok(!tcp_socketpair(&s, &s2), "Test[%d]: creating socket pair failed\n", i); + else + { + s = socket(AF_INET, sock_type[i], 0); + ok (s != SOCKET_ERROR, "Test[%d]: failed to create socket\n", i); + ok (!bind(s, (struct sockaddr*) &address, sizeof(address)), "Test[%d]: bind failed\n", i); + } + event = WSACreateEvent(); + ok (event != NULL, "Test[%d]: failed to create event\n", i); + for (j = 0; j < 5; j++) /* Repeat sometimes and the result must be the same */ + { + /* When the TCP socket is not connected NO events will be returned. + * When connected and no data pending it will get the write event. + * UDP sockets don't have connections so as soon as they are bound + * they can read/write data. Since nobody is sendind us data only + * the write event will be returned and ONLY once. + */ + ok (!WSAEventSelect(s, event, FD_READ | FD_WRITE), "Test[%d]: WSAEventSelect failed\n", i); + memset(&net_events, 0xAB, sizeof(net_events)); + ok (!WSAEnumNetworkEvents(s, l == 0 ? event : NULL, &net_events), + "Test[%d]: WSAEnumNetworkEvents failed\n", i); + if (i >= 1 && j == 0) /* FD_WRITE is SET on first try for UDP and connected TCP */ + { + todo_wine_if (i == 0 || net_events.lNetworkEvents == 0) + ok (net_events.lNetworkEvents == FD_WRITE, "Test[%d]: expected 2, got %d\n", + i, net_events.lNetworkEvents); + } + else + { + todo_wine_if (i != 0 && net_events.lNetworkEvents != 0) + ok (net_events.lNetworkEvents == 0, "Test[%d]: expected 0, got %d\n", + i, net_events.lNetworkEvents); + } + for (k = 0; k < FD_MAX_EVENTS; k++) + { + if (i >= 1 && j == 0 && k == 1) /* first UDP and connected TCP test, FD_WRITE bit no error*/ + { + ok (net_events.iErrorCode[k] == 0x0, "Test[%d][%d]: expected 0x0, got 0x%x\n", + i, k, net_events.iErrorCode[k]); + } + else + { + /* Bits that are not set in lNetworkEvents MUST not be changed */ + todo_wine + ok (net_events.iErrorCode[k] == 0xABABABAB, "Test[%d][%d]: expected 0xABABABAB, got 0x%x\n", + i, k, net_events.iErrorCode[k]); + } + } + } + closesocket(s); + WSACloseEvent(event); + if (i == 2) closesocket(s2); + } + } +} + static void test_WSAAddressToStringA(void) { SOCKET v6 = INVALID_SOCKET; @@ -2846,6 +3223,7 @@ static void test_WSAStringToAddressA(void) CHAR address6[] = "::1"; CHAR address7[] = "[::1]"; CHAR address8[] = "[::1]:65535"; + CHAR address9[] = "2001::1"; len = 0; sockaddr.sin_family = AF_INET; @@ -2929,6 +3307,12 @@ static void test_WSAStringToAddressA(void) (ret == SOCKET_ERROR && GLE == WSAEINVAL), "WSAStringToAddressA() failed for IPv6 address: %d\n", GLE); + len = sizeof(sockaddr); + + ret = WSAStringToAddressA( address9, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + GLE = WSAGetLastError(); + ok( (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressA() should have failed with %d\n", GLE ); } static void test_WSAStringToAddressW(void) @@ -2949,6 +3333,7 @@ static void test_WSAStringToAddressW(void) WCHAR address6[] = {':',':','1','\0'}; WCHAR address7[] = {'[',':',':','1',']','\0'}; WCHAR address8[] = {'[',':',':','1',']',':','6','5','5','3','5','\0'}; + WCHAR address9[] = {'2','0','0','1',':',':','1','\0'}; len = 0; sockaddr.sin_family = AF_INET; @@ -3045,6 +3430,12 @@ static void test_WSAStringToAddressW(void) (ret == SOCKET_ERROR && GLE == WSAEINVAL), "WSAStringToAddressW() failed for IPv6 address: %d\n", GLE); + len = sizeof(sockaddr); + + ret = WSAStringToAddressW( address9, AF_INET, NULL, (SOCKADDR*)&sockaddr, &len ); + GLE = WSAGetLastError(); + ok( (ret == SOCKET_ERROR && GLE == WSAEINVAL), + "WSAStringToAddressW() should have failed with %d\n", GLE ); } static DWORD WINAPI SelectReadThread(void *param) @@ -3073,6 +3464,14 @@ static DWORD WINAPI SelectReadThread(void *param) return 0; } +static DWORD WINAPI SelectCloseThread(void *param) +{ + SOCKET s = *(SOCKET*)param; + Sleep(500); + closesocket(s); + return 0; +} + static void test_errors(void) { SOCKET sock; @@ -3195,47 +3594,61 @@ static void test_listen(void) ok (ret == 0, "closesocket failed unexpectedly: %d\n", ret); } +#define FD_ZERO_ALL() { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); } +#define FD_SET_ALL(s) { FD_SET(s, &readfds); FD_SET(s, &writefds); FD_SET(s, &exceptfds); } static void test_select(void) { - SOCKET fdRead, fdWrite; + static char tmp_buf[1024]; + + SOCKET fdListen, fdRead, fdWrite; fd_set readfds, writefds, exceptfds; unsigned int maxfd; - int ret; + int ret, len; char buffer; struct timeval select_timeout; + struct sockaddr_in address; select_thread_params thread_params; HANDLE thread_handle; - DWORD id; + DWORD ticks, id; fdRead = socket(AF_INET, SOCK_STREAM, 0); ok( (fdRead != INVALID_SOCKET), "socket failed unexpectedly: %d\n", WSAGetLastError() ); fdWrite = socket(AF_INET, SOCK_STREAM, 0); ok( (fdWrite != INVALID_SOCKET), "socket failed unexpectedly: %d\n", WSAGetLastError() ); - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); - FD_SET(fdRead, &readfds); - FD_SET(fdWrite, &writefds); - FD_SET(fdRead, &exceptfds); - FD_SET(fdWrite, &exceptfds); - select_timeout.tv_sec=0; - select_timeout.tv_usec=500; maxfd = fdRead; if (fdWrite > maxfd) maxfd = fdWrite; - - todo_wine { - ret = select(maxfd+1, &readfds, &writefds, &exceptfds, &select_timeout); - ok ( (ret == 0), "select should not return any socket handles\n"); - ok ( !FD_ISSET(fdRead, &readfds), "FD should not be set\n"); - } - ok ( !FD_ISSET(fdWrite, &writefds), "FD should not be set\n"); - ok ( !FD_ISSET(fdRead, &exceptfds), "FD should not be set\n"); - ok ( !FD_ISSET(fdWrite, &exceptfds), "FD should not be set\n"); + FD_ZERO_ALL(); + FD_SET_ALL(fdRead); + FD_SET_ALL(fdWrite); + select_timeout.tv_sec=0; + select_timeout.tv_usec=0; + + ticks = GetTickCount(); + ret = select(maxfd+1, &readfds, &writefds, &exceptfds, &select_timeout); + ticks = GetTickCount() - ticks; + ok(ret == 0, "select should not return any socket handles\n"); + ok(ticks < 10, "select was blocking for %u ms, expected < 10 ms\n", ticks); + ok(!FD_ISSET(fdRead, &readfds), "FD should not be set\n"); + ok(!FD_ISSET(fdWrite, &writefds), "FD should not be set\n"); + ok(!FD_ISSET(fdRead, &exceptfds), "FD should not be set\n"); + ok(!FD_ISSET(fdWrite, &exceptfds), "FD should not be set\n"); + FD_ZERO_ALL(); + FD_SET_ALL(fdRead); + FD_SET_ALL(fdWrite); + select_timeout.tv_sec=0; + select_timeout.tv_usec=500; + + ret = select(maxfd+1, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 0, "select should not return any socket handles\n"); + ok(!FD_ISSET(fdRead, &readfds), "FD should not be set\n"); + ok(!FD_ISSET(fdWrite, &writefds), "FD should not be set\n"); + ok(!FD_ISSET(fdRead, &exceptfds), "FD should not be set\n"); + ok(!FD_ISSET(fdWrite, &exceptfds), "FD should not be set\n"); + ok ((listen(fdWrite, SOMAXCONN) == SOCKET_ERROR), "listen did not fail\n"); ret = closesocket(fdWrite); ok ( (ret == 0), "closesocket failed unexpectedly: %d\n", ret); @@ -3259,9 +3672,7 @@ static void test_select(void) ok( (ret == -1), "peek at closed socket expected -1 got %d\n", ret); /* Test selecting invalid handles */ - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); + FD_ZERO_ALL(); SetLastError(0); ret = select(maxfd+1, 0, 0, 0, &select_timeout); @@ -3295,7 +3706,278 @@ static void test_select(void) ok ( (ret == SOCKET_ERROR), "expected SOCKET_ERROR, got %i\n", ret); ok ( WSAGetLastError() == WSAENOTSOCK, "expected WSAENOTSOCK, got %i\n", WSAGetLastError()); ok ( !FD_ISSET(fdRead, &exceptfds), "FD should not be set\n"); + + ok(!tcp_socketpair(&fdRead, &fdWrite), "creating socket pair failed\n"); + maxfd = fdRead; + if(fdWrite > maxfd) maxfd = fdWrite; + + FD_ZERO(&readfds); + FD_SET(fdRead, &readfds); + ret = select(fdRead+1, &readfds, NULL, NULL, &select_timeout); + ok(!ret, "select returned %d\n", ret); + + FD_ZERO(&writefds); + FD_SET(fdWrite, &writefds); + ret = select(fdWrite+1, NULL, &writefds, NULL, &select_timeout); + ok(ret == 1, "select returned %d\n", ret); + ok(FD_ISSET(fdWrite, &writefds), "fdWrite socket is not in the set\n"); + + /* tests for overlapping fd_set pointers */ + FD_ZERO(&readfds); + FD_SET(fdWrite, &readfds); + ret = select(fdWrite+1, &readfds, &readfds, NULL, &select_timeout); + ok(ret == 1, "select returned %d\n", ret); + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); + + FD_ZERO(&readfds); + FD_SET(fdWrite, &readfds); + FD_SET(fdRead, &readfds); + ret = select(maxfd+1, &readfds, &readfds, NULL, &select_timeout); + ok(ret == 2, "select returned %d\n", ret); + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + + ok(send(fdWrite, "test", 4, 0) == 4, "failed to send data\n"); + FD_ZERO(&readfds); + FD_SET(fdRead, &readfds); + ret = select(fdRead+1, &readfds, NULL, NULL, &select_timeout); + ok(ret == 1, "select returned %d\n", ret); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + + FD_ZERO(&readfds); + FD_SET(fdWrite, &readfds); + FD_SET(fdRead, &readfds); + ret = select(maxfd+1, &readfds, &readfds, NULL, &select_timeout); + ok(ret == 2, "select returned %d\n", ret); + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + +#if ROSTESTS_233_IS_FIXED + while(1) { + FD_ZERO(&writefds); + FD_SET(fdWrite, &writefds); + ret = select(fdWrite+1, NULL, &writefds, NULL, &select_timeout); + if(!ret) break; + ok(send(fdWrite, tmp_buf, sizeof(tmp_buf), 0) > 0, "failed to send data\n"); + } +#endif /* ROSTESTS_233_IS_FIXED */ + + FD_ZERO(&readfds); + FD_SET(fdWrite, &readfds); + FD_SET(fdRead, &readfds); + ret = select(maxfd+1, &readfds, &readfds, NULL, &select_timeout); + ok(ret == 1, "select returned %d\n", ret); + ok(!FD_ISSET(fdWrite, &readfds), "fdWrite socket is in the set\n"); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + + ok(send(fdRead, "test", 4, 0) == 4, "failed to send data\n"); + Sleep(100); + FD_ZERO(&readfds); + FD_SET(fdWrite, &readfds); + FD_SET(fdRead, &readfds); + ret = select(maxfd+1, &readfds, &readfds, NULL, &select_timeout); + ok(ret == 2, "select returned %d\n", ret); + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + + closesocket(fdRead); + closesocket(fdWrite); + + /* select() works in 3 distinct states: + * - to check if a connection attempt ended with success or error; + * - to check if a pending connection is waiting for acceptance; + * - to check for data to read, availability for write and OOB data + * + * The tests below ensure that all conditions are tested. + */ + 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); + select_timeout.tv_sec = 1; + select_timeout.tv_usec = 250000; + + /* When no events are pending select returns 0 with no error */ + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 0, "expected 0, got %d\n", ret); + + /* When a socket is attempting to connect the listening socket receives the read descriptor */ + fdWrite = setup_connector_socket(&address, len, TRUE); + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdListen, &readfds), "fdListen socket is not in the set\n"); + len = sizeof(address); + fdRead = accept(fdListen, (struct sockaddr*) &address, &len); + ok(fdRead != INVALID_SOCKET, "expected a valid socket\n"); + + /* The connector is signaled through the write descriptor */ + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + FD_SET_ALL(fdRead); + FD_SET_ALL(fdWrite); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 2, "expected 2, got %d\n", ret); + ok(FD_ISSET(fdWrite, &writefds), "fdWrite socket is not in the set\n"); + ok(FD_ISSET(fdRead, &writefds), "fdRead socket is not in the set\n"); + len = sizeof(id); + id = 0xdeadbeef; + ret = getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char*)&id, &len); + ok(!ret, "getsockopt failed with %d\n", WSAGetLastError()); + ok(id == 0, "expected 0, got %d\n", id); + + /* When data is received the receiver gets the read descriptor */ + ret = send(fdWrite, "1234", 4, 0); + ok(ret == 4, "expected 4, got %d\n", ret); + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + FD_SET(fdRead, &readfds); + FD_SET(fdRead, &exceptfds); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\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"); + + /* When OOB data is received the socket is set in the except descriptor */ + ret = send(fdWrite, "A", 1, MSG_OOB); + ok(ret == 1, "expected 1, got %d\n", ret); + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + FD_SET(fdRead, &readfds); + FD_SET(fdRead, &exceptfds); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdRead, &exceptfds), "fdRead socket is not in the set\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 it will not receive the OOB in except fds */ + 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); + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + FD_SET(fdRead, &readfds); + FD_SET(fdRead, &exceptfds); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdRead, &readfds), "fdRead socket is not in the set\n"); + tmp_buf[0] = 0xAF; + SetLastError(0xdeadbeef); + ret = recv(fdRead, tmp_buf, sizeof(tmp_buf), MSG_OOB); + if (ret == SOCKET_ERROR) /* can't recv with MSG_OOB if OOBINLINED */ + { + 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]); + } + else ok(broken(ret == 1) /* <= NT4 */, "expected error, got 1\n"); + + /* When the connection is closed the socket is set in the read descriptor */ + ret = closesocket(fdRead); + ok(ret == 0, "expected 0, got %d\n", ret); + FD_ZERO_ALL(); + FD_SET_ALL(fdListen); + FD_SET(fdWrite, &readfds); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\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 it will get to the except descriptor */ + 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); + FD_ZERO_ALL(); + FD_SET(fdWrite, &writefds); + FD_SET(fdWrite, &exceptfds); + select_timeout.tv_sec = 2; /* requires more time to realize it will not connect */ + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + len = sizeof(id); + id = 0xdeadbeef; + ret = getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char*)&id, &len); + ok(!ret, "getsockopt failed with %d\n", WSAGetLastError()); + ok(id == WSAECONNREFUSED, "expected 10061, got %d\n", id); + ok(FD_ISSET(fdWrite, &exceptfds), "fdWrite socket is not in the set\n"); + ok(select_timeout.tv_usec == 250000, "select timeout should not have changed\n"); + closesocket(fdWrite); + + /* Try select() on a closed socket after connection */ + ok(!tcp_socketpair(&fdRead, &fdWrite), "creating socket pair failed\n"); + closesocket(fdRead); + FD_ZERO_ALL(); + FD_SET_ALL(fdWrite); + FD_SET_ALL(fdRead); + SetLastError(0xdeadbeef); + ret = select(0, &readfds, NULL, &exceptfds, &select_timeout); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); +todo_wine + ok(GetLastError() == WSAENOTSOCK, "expected 10038, got %d\n", GetLastError()); + /* descriptor sets are unchanged */ + ok(readfds.fd_count == 2, "expected 2, got %d\n", readfds.fd_count); + ok(exceptfds.fd_count == 2, "expected 2, got %d\n", exceptfds.fd_count); + closesocket(fdWrite); + +#if ROSTESTS_233_IS_FIXED + + /* Close the socket currently being selected in a thread - bug 38399 */ + 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()); + FD_ZERO_ALL(); + FD_SET_ALL(fdWrite); + ret = select(0, &readfds, NULL, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdWrite, &readfds), "fdWrite socket is not in the set\n"); + WaitForSingleObject (thread_handle, 1000); + closesocket(fdRead); + /* test again with only the except descriptor */ + 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()); + FD_ZERO_ALL(); + FD_SET(fdWrite, &exceptfds); + SetLastError(0xdeadbeef); + ret = select(0, NULL, NULL, &exceptfds, &select_timeout); +todo_wine + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); +todo_wine + ok(GetLastError() == WSAENOTSOCK, "expected 10038, got %d\n", GetLastError()); + WaitForSingleObject (thread_handle, 1000); + closesocket(fdRead); + +#endif /* ROSTESTS_233_IS_FIXED */ + + /* test UDP behavior of unbound sockets */ + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 250000; + fdWrite = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ok(fdWrite != INVALID_SOCKET, "socket call failed\n"); + FD_ZERO_ALL(); + FD_SET_ALL(fdWrite); + ret = select(0, &readfds, &writefds, &exceptfds, &select_timeout); + ok(ret == 1, "expected 1, got %d\n", ret); + ok(FD_ISSET(fdWrite, &writefds), "fdWrite socket is not in the set\n"); + closesocket(fdWrite); } +#undef FD_SET_ALL +#undef FD_ZERO_ALL static DWORD WINAPI AcceptKillThread(void *param) { @@ -3366,7 +4048,7 @@ static SOCKET setup_server_socket(struct sockaddr_in *addr, int *len) return server_socket; } -static SOCKET setup_connector_socket(struct sockaddr_in *addr, int len) +static SOCKET setup_connector_socket(struct sockaddr_in *addr, int len, BOOL nonblock) { int ret; SOCKET connector; @@ -3374,8 +4056,18 @@ static SOCKET setup_connector_socket(struct sockaddr_in *addr, int len) connector = socket(AF_INET, SOCK_STREAM, 0); ok(connector != INVALID_SOCKET, "failed to create connector socket %d\n", WSAGetLastError()); + if (nonblock) + set_blocking(connector, !nonblock); + ret = connect(connector, (struct sockaddr *)addr, len); - ok(!ret, "connecting to accepting socket failed %d\n", WSAGetLastError()); + if (!nonblock) + ok(!ret, "connecting to accepting socket failed %d\n", WSAGetLastError()); + else if (ret == SOCKET_ERROR) + { + DWORD error = WSAGetLastError(); + ok(error == WSAEWOULDBLOCK || error == WSAEINPROGRESS, + "expected 10035 or 10036, got %d\n", error); + } return connector; } @@ -3403,7 +4095,7 @@ static void test_accept(void) return; } - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; trace("Blocking accept next\n"); @@ -3445,13 +4137,13 @@ static void test_accept(void) closesocket(accepted); closesocket(connector); - accepted = connector = server_socket = INVALID_SOCKET; + accepted = connector = INVALID_SOCKET; socklen = sizeof(address); server_socket = setup_server_socket(&address, &socklen); if (server_socket == INVALID_SOCKET) goto done; - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; socklen = 0; @@ -3462,7 +4154,7 @@ static void test_accept(void) connector = INVALID_SOCKET; socklen = sizeof(address); - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; accepted = WSAAccept(server_socket, NULL, NULL, NULL, 0); @@ -3472,7 +4164,7 @@ static void test_accept(void) accepted = connector = INVALID_SOCKET; socklen = sizeof(address); - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; socklen = sizeof(ss); @@ -3486,7 +4178,7 @@ static void test_accept(void) accepted = connector = INVALID_SOCKET; socklen = sizeof(address); - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; socklen = 0; @@ -3497,7 +4189,7 @@ static void test_accept(void) accepted = connector = INVALID_SOCKET; socklen = sizeof(address); - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; accepted = accept(server_socket, NULL, NULL); @@ -3507,7 +4199,7 @@ static void test_accept(void) accepted = connector = INVALID_SOCKET; socklen = sizeof(address); - connector = setup_connector_socket(&address, socklen); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; socklen = sizeof(ss); @@ -3656,6 +4348,7 @@ static void test_getsockname(void) int sa_get_len = sa_set_len; static const unsigned char null_padding[] = {0,0,0,0,0,0,0,0}; int ret; + struct hostent *h; if(WSAStartup(MAKEWORD(2,0), &wsa)){ trace("Winsock failed: %d. Aborting test\n", WSAGetLastError()); @@ -3703,6 +4396,38 @@ static void test_getsockname(void) "getsockname did not zero the sockaddr_in structure\n"); closesocket(sock); + + h = gethostbyname(""); + if (h && h->h_length == 4) /* this test is only meaningful in IPv4 */ + { + int i; + for (i = 0; h->h_addr_list[i]; i++) + { + char ipstr[32]; + struct in_addr ip; + ip.s_addr = *(ULONG *) h->h_addr_list[i]; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + ok(sock != INVALID_SOCKET, "socket failed with %d\n", GetLastError()); + + memset(&sa_set, 0, sizeof(sa_set)); + sa_set.sin_family = AF_INET; + sa_set.sin_addr.s_addr = ip.s_addr; + /* The same address we bind must be the same address we get */ + ret = bind(sock, (struct sockaddr*)&sa_set, sizeof(sa_set)); + ok(ret == 0, "bind failed with %d\n", GetLastError()); + sa_get_len = sizeof(sa_get); + ret = getsockname(sock, (struct sockaddr*)&sa_get, &sa_get_len); + ok(ret == 0, "getsockname failed with %d\n", GetLastError()); + strcpy(ipstr, inet_ntoa(sa_get.sin_addr)); + trace("testing bind on interface %s\n", ipstr); + ok(sa_get.sin_addr.s_addr == sa_set.sin_addr.s_addr, + "address does not match: %s != %s\n", ipstr, inet_ntoa(sa_set.sin_addr)); + + closesocket(sock); + } + } + WSACleanup(); } @@ -3762,28 +4487,124 @@ static void test_dns(void) int WINAPI gethostname(char *name, int namelen); #endif -static void test_gethostbyname_hack(void) +static void test_gethostbyname(void) { struct hostent *he; - char name[256]; - static BYTE loopback[] = {127, 0, 0, 1}; - static BYTE magic_loopback[] = {127, 12, 34, 56}; - int ret; - - ret = gethostname(name, 256); + struct in_addr **addr_list; + char name[256], first_ip[16]; + int ret, i, count; + PMIB_IPFORWARDTABLE routes = NULL; + PIP_ADAPTER_INFO adapters = NULL, k; + DWORD adap_size = 0, route_size = 0; + BOOL found_default = FALSE; + BOOL local_ip = FALSE; + + ret = gethostname(name, sizeof(name)); ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); - he = gethostbyname("localhost"); - ok(he != NULL, "gethostbyname(\"localhost\") failed: %d\n", h_errno); - if(he) + he = gethostbyname(name); + ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); +#ifdef __REACTOS__ /* ROSTESTS-233 */ + if (he != NULL) { - if(he->h_length != 4) +#endif + addr_list = (struct in_addr **)he->h_addr_list; + strcpy(first_ip, inet_ntoa(*addr_list[0])); + + trace("List of local IPs:\n"); + for(count = 0; addr_list[count] != NULL; count++) { - skip("h_length is %d, not IPv4, skipping test.\n", he->h_length); - return; + char *ip = inet_ntoa(*addr_list[count]); + if (!strcmp(ip, "127.0.0.1")) + local_ip = TRUE; + trace("%s\n", ip); } +#ifdef __REACTOS__ /* ROSTESTS-233 */ + } +#endif - ok(memcmp(he->h_addr_list[0], loopback, he->h_length) == 0, + if (local_ip) + { + ok (count == 1, "expected 127.0.0.1 to be the only IP returned\n"); + skip("Only the loopback address is present, skipping tests\n"); + return; + } + + if (!pGetAdaptersInfo || !pGetIpForwardTable) + { + win_skip("GetAdaptersInfo and/or GetIpForwardTable not found, skipping tests\n"); + return; + } + + ret = pGetAdaptersInfo(NULL, &adap_size); + ok (ret == ERROR_BUFFER_OVERFLOW, "GetAdaptersInfo failed with a different error: %d\n", ret); + ret = pGetIpForwardTable(NULL, &route_size, FALSE); + ok (ret == ERROR_INSUFFICIENT_BUFFER, "GetIpForwardTable failed with a different error: %d\n", ret); + + adapters = HeapAlloc(GetProcessHeap(), 0, adap_size); + routes = HeapAlloc(GetProcessHeap(), 0, route_size); + + ret = pGetAdaptersInfo(adapters, &adap_size); + ok (ret == NO_ERROR, "GetAdaptersInfo failed, error: %d\n", ret); + ret = pGetIpForwardTable(routes, &route_size, FALSE); + ok (ret == NO_ERROR, "GetIpForwardTable failed, error: %d\n", ret); + + /* This test only has meaning if there is more than one IP configured */ + if (adapters->Next == NULL && count == 1) + { + skip("Only one IP is present, skipping tests\n"); + goto cleanup; + } + + for (i = 0; !found_default && i < routes->dwNumEntries; i++) + { + /* default route (ip 0.0.0.0) ? */ + if (routes->table[i].dwForwardDest) continue; + + for (k = adapters; k != NULL; k = k->Next) + { + char *ip; + + if (k->Index != routes->table[i].dwForwardIfIndex) continue; + + /* the first IP returned from gethostbyname must be a default route */ + ip = k->IpAddressList.IpAddress.String; + if (!strcmp(first_ip, ip)) + { + found_default = TRUE; + break; + } + } + } + ok (found_default, "failed to find the first IP from gethostbyname!\n"); + +cleanup: + HeapFree(GetProcessHeap(), 0, adapters); + HeapFree(GetProcessHeap(), 0, routes); +} + +static void test_gethostbyname_hack(void) +{ + struct hostent *he; + char name[256]; + static BYTE loopback[] = {127, 0, 0, 1}; + static BYTE magic_loopback[] = {127, 12, 34, 56}; + int ret; + + ret = gethostname(name, 256); + ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); + + he = gethostbyname("localhost"); + ok(he != NULL, "gethostbyname(\"localhost\") failed: %d\n", h_errno); + if(he) + { + if(he->h_length != 4) + { + skip("h_length is %d, not IPv4, skipping test.\n", he->h_length); + return; + } + + ok(memcmp(he->h_addr_list[0], loopback, he->h_length) == 0, "gethostbyname(\"localhost\") returned %d.%d.%d.%d\n", he->h_addr_list[0][0], he->h_addr_list[0][1], he->h_addr_list[0][2], he->h_addr_list[0][3]); @@ -3795,7 +4616,6 @@ static void test_gethostbyname_hack(void) return; } - he = NULL; he = gethostbyname(name); ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, h_errno); if(he) @@ -3820,6 +4640,39 @@ static void test_gethostbyname_hack(void) * resolve nonexistent host names to addresses of the ISP's spam pages. */ } +static void test_gethostname(void) +{ + struct hostent *he; + char name[256]; + int ret, len; + + WSASetLastError(0xdeadbeef); + ret = gethostname(NULL, 256); + ok(ret == -1, "gethostname() returned %d\n", ret); + ok(WSAGetLastError() == WSAEFAULT, "gethostname with null buffer " + "failed with %d, expected %d\n", WSAGetLastError(), WSAEFAULT); + + ret = gethostname(name, sizeof(name)); + ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); + he = gethostbyname(name); + ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); + + len = strlen(name); + WSASetLastError(0xdeadbeef); + strcpy(name, "deadbeef"); + ret = gethostname(name, len); + ok(ret == -1, "gethostname() returned %d\n", ret); + ok(!strcmp(name, "deadbeef"), "name changed unexpected!\n"); + ok(WSAGetLastError() == WSAEFAULT, "gethostname with insufficient length " + "failed with %d, expected %d\n", WSAGetLastError(), WSAEFAULT); + + len++; + ret = gethostname(name, len); + ok(ret == 0, "gethostname() call failed: %d\n", WSAGetLastError()); + he = gethostbyname(name); + ok(he != NULL, "gethostbyname(\"%s\") failed: %d\n", name, WSAGetLastError()); +} + static void test_inet_addr(void) { u_long addr; @@ -3959,6 +4812,137 @@ static void test_addr_to_print(void) pdst = pInetNtop(AF_INET6, (void*)&in6.s6_addr, dst6, 18); ok(pdst != NULL, "The pointer should be returned (%p)\n", pdst); } +static void test_inet_pton(void) +{ + struct TEST_DATA + { + int family, ret; + DWORD err; + const char *printable, *collapsed, *raw_data; + } tests[] = { + {AF_UNSPEC, -1, WSAEFAULT, /* Test 0 */ + NULL, NULL, NULL}, + {AF_INET, -1, WSAEFAULT, + NULL, NULL, NULL}, + {AF_INET6, -1, WSAEFAULT, + NULL, NULL, NULL}, + {AF_UNSPEC, -1, WSAEAFNOSUPPORT, + "127.0.0.1", NULL, NULL}, + {AF_INET, 1, 0, + "127.0.0.1", "127.0.0.1", + "\x7f\x00\x00\x01"}, + {AF_INET6, 0, 0, + "127.0.0.1", "127.0.0.1", NULL}, + {AF_INET, 0, 0, + "::1/128", NULL, NULL}, + {AF_INET6, 0, 0, + "::1/128", NULL, NULL}, + {AF_UNSPEC, -1, WSAEAFNOSUPPORT, + "broken", NULL, NULL}, + {AF_INET, 0, 0, + "broken", NULL, NULL}, + {AF_INET6, 0, 0, /* Test 10 */ + "broken", NULL, NULL}, + {AF_UNSPEC, -1, WSAEAFNOSUPPORT, + "177.32.45.20", NULL, NULL}, + {AF_INET, 1, 0, + "177.32.45.20", "177.32.45.20", + "\xb1\x20\x2d\x14"}, + {AF_INET6, 0, 0, + "177.32.45.20", NULL, NULL}, + {AF_INET, 0, 0, + "2607:f0d0:1002:51::4", NULL, NULL}, + {AF_INET6, 1, 0, + "2607:f0d0:1002:51::4", "2607:f0d0:1002:51::4", + "\x26\x07\xf0\xd0\x10\x02\x00\x51\x00\x00\x00\x00\x00\x00\x00\x04"}, + {AF_INET, 0, 0, + "::177.32.45.20", NULL, NULL}, + {AF_INET6, 1, 0, + "::177.32.45.20", "::177.32.45.20", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\x20\x2d\x14"}, + {AF_INET, 0, 0, + "fe80::0202:b3ff:fe1e:8329", NULL, NULL}, + {AF_INET6, 1, 0, + "fe80::0202:b3ff:fe1e:8329", "fe80::202:b3ff:fe1e:8329", + "\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x02\xb3\xff\xfe\x1e\x83\x29"}, + {AF_INET6, 1, 0, /* Test 20 */ + "fe80::202:b3ff:fe1e:8329", "fe80::202:b3ff:fe1e:8329", + "\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x02\xb3\xff\xfe\x1e\x83\x29"}, + {AF_INET, 0, 0, + "a", NULL, NULL}, + {AF_INET, 0, 0, + "a.b", NULL, NULL}, + {AF_INET, 0, 0, + "a.b.c", NULL, NULL}, + {AF_INET, 0, 0, + "a.b.c.d", NULL, NULL}, + {AF_INET6, 1, 0, + "2001:cdba:0000:0000:0000:0000:3257:9652", "2001:cdba::3257:9652", + "\x20\x01\xcd\xba\x00\x00\x00\x00\x00\x00\x00\x00\x32\x57\x96\x52"}, + {AF_INET6, 1, 0, + "2001:cdba::3257:9652", "2001:cdba::3257:9652", + "\x20\x01\xcd\xba\x00\x00\x00\x00\x00\x00\x00\x00\x32\x57\x96\x52"}, + {AF_INET6, 1, 0, + "2001:cdba:0:0:0:0:3257:9652", "2001:cdba::3257:9652", + "\x20\x01\xcd\xba\x00\x00\x00\x00\x00\x00\x00\x00\x32\x57\x96\x52"} + }; + int i, ret; + DWORD err; + char buffer[64],str[64]; + WCHAR printableW[64]; + const char *ptr; + + /* InetNtop and InetPton became available in Vista and Win2008 */ + if (!pInetNtop || !pInetPtonA || !pInetPtonW) + { + win_skip("InetNtop and/or InetPton not present, not executing tests\n"); + return; + } + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + WSASetLastError(0xdeadbeef); + ret = pInetPtonA(tests[i].family, tests[i].printable, buffer); + ok (ret == tests[i].ret, "Test [%d]: Expected %d, got %d\n", i, tests[i].ret, ret); + if (tests[i].ret == -1) + { + err = WSAGetLastError(); + ok (tests[i].err == err, "Test [%d]: Expected 0x%x, got 0x%x\n", i, tests[i].err, err); + } + if (tests[i].ret != 1) continue; + ok (memcmp(buffer, tests[i].raw_data, + tests[i].family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)) == 0, + "Test [%d]: Expected binary data differs\n", i); + + /* Test the result from Pton with Ntop */ + strcpy (str, "deadbeef"); + ptr = pInetNtop(tests[i].family, buffer, str, sizeof(str)); + ok (ptr != NULL, "Test [%d]: Failed with NULL\n", i); + ok (ptr == str, "Test [%d]: Pointers differ (%p != %p)\n", i, ptr, str); + if (!ptr) continue; + ok (strcmp(ptr, tests[i].collapsed) == 0, "Test [%d]: Expected '%s', got '%s'\n", + i, tests[i].collapsed, ptr); + } + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) + { + if (tests[i].printable) + MultiByteToWideChar(CP_ACP, 0, tests[i].printable, -1, printableW, + sizeof(printableW) / sizeof(printableW[0])); + WSASetLastError(0xdeadbeef); + ret = pInetPtonW(tests[i].family, tests[i].printable ? printableW : NULL, buffer); + ok(ret == tests[i].ret, "Test [%d]: Expected %d, got %d\n", i, tests[i].ret, ret); + if (tests[i].ret == -1) + { + err = WSAGetLastError(); + ok(tests[i].err == err, "Test [%d]: Expected 0x%x, got 0x%x\n", i, tests[i].err, err); + } + if (tests[i].ret != 1) continue; + ok(memcmp(buffer, tests[i].raw_data, + tests[i].family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)) == 0, + "Test [%d]: Expected binary data differs\n", i); + } +} static void test_ioctlsocket(void) { @@ -3966,7 +4950,9 @@ static void test_ioctlsocket(void) struct tcp_keepalive kalive; int ret, optval; static const LONG cmds[] = {FIONBIO, FIONREAD, SIOCATMARK}; - UINT i; + UINT i, bytes_rec; + char data; + WSABUF bufs; u_long arg = 0; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -4008,6 +4994,7 @@ static void test_ioctlsocket(void) ok(ret != SOCKET_ERROR, "setsockopt failed unexpectedly\n"); arg = 0; ret = ioctlsocket(sock, SIOCATMARK, &arg); + ok(ret != SOCKET_ERROR, "ioctlsocket failed unexpectedly\n"); ok(arg, "SIOCATMARK expected a non-zero value\n"); ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &arg, 0, NULL, 0, &arg, NULL, NULL); @@ -4066,6 +5053,39 @@ static void test_ioctlsocket(void) ok(ret == 0, "WSAIoctl failed unexpectedly with error %d\n", WSAGetLastError()); ok(optval == 4, "FIONREAD should have returned 4 bytes, got %d instead\n", optval); + /* trying to read from an OOB inlined socket with MSG_OOB results in WSAEINVAL */ + set_blocking(dst, FALSE); + i = MSG_OOB; + SetLastError(0xdeadbeef); + ret = recv(dst, &data, 1, i); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ret = GetLastError(); + ok(ret == WSAEWOULDBLOCK, "expected 10035, got %d\n", ret); + bufs.len = sizeof(char); + bufs.buf = &data; + ret = WSARecv(dst, &bufs, 1, &bytes_rec, &i, NULL, NULL); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ret = GetLastError(); + ok(ret == WSAEWOULDBLOCK, "expected 10035, got %d\n", ret); + optval = 1; + ret = setsockopt(dst, SOL_SOCKET, SO_OOBINLINE, (void *)&optval, sizeof(optval)); + ok(ret != SOCKET_ERROR, "setsockopt failed unexpectedly\n"); + i = MSG_OOB; + SetLastError(0xdeadbeef); + ret = recv(dst, &data, 1, i); + if (ret == SOCKET_ERROR) + { + ret = GetLastError(); + ok(ret == WSAEINVAL, "expected 10022, got %d\n", ret); + bufs.len = sizeof(char); + bufs.buf = &data; + ret = WSARecv(dst, &bufs, 1, &bytes_rec, &i, NULL, NULL); + ok(ret == SOCKET_ERROR, "expected -1, got %d\n", ret); + ret = GetLastError(); + ok(ret == WSAEINVAL, "expected 10022, got %d\n", ret); + } + else ok(broken(ret == 1) /* <= NT4 */, "expected error, got 1\n"); + closesocket(dst); optval = 0xdeadbeef; ret = WSAIoctl(dst, FIONREAD, NULL, 0, &optval, sizeof(optval), &arg, NULL, NULL); @@ -4113,6 +5133,8 @@ static void test_send(void) OVERLAPPED ov; BOOL bret; DWORD id, bytes_sent, dwRet; + DWORD expected_time, connect_time; + socklen_t optlen; memset(&ov, 0, sizeof(ov)); @@ -4121,6 +5143,7 @@ static void test_send(void) ok(0, "creating socket pair failed, skipping test\n"); return; } + expected_time = GetTickCount(); set_blocking(dst, FALSE); /* force disable buffering so we can get a pending overlapped request */ @@ -4207,13 +5230,33 @@ static void test_send(void) ok(ret == SOCKET_ERROR && WSAGetLastError() == ERROR_IO_PENDING, "Failed to start overlapped send %d - %d\n", ret, WSAGetLastError()); + expected_time = (GetTickCount() - expected_time) / 1000; + + connect_time = 0xdeadbeef; + optlen = sizeof(connect_time); + ret = getsockopt(dst, SOL_SOCKET, SO_CONNECT_TIME, (char *)&connect_time, &optlen); + ok(!ret, "getsockopt failed %d\n", WSAGetLastError()); + ok(connect_time >= expected_time && connect_time <= expected_time + 1, + "unexpected connect time %u, expected %u\n", connect_time, expected_time); + + connect_time = 0xdeadbeef; + optlen = sizeof(connect_time); + ret = getsockopt(src, SOL_SOCKET, SO_CONNECT_TIME, (char *)&connect_time, &optlen); + ok(!ret, "getsockopt failed %d\n", WSAGetLastError()); + ok(connect_time >= expected_time && connect_time <= expected_time + 1, + "unexpected connect time %u, expected %u\n", connect_time, expected_time); + end: if (src != INVALID_SOCKET) closesocket(src); if (dst != INVALID_SOCKET) closesocket(dst); if (hThread != NULL) + { + dwRet = WaitForSingleObject(hThread, 500); + ok(dwRet == WAIT_OBJECT_0, "failed to wait for thread termination: %d\n", GetLastError()); CloseHandle(hThread); + } if (ov.hEvent) CloseHandle(ov.hEvent); HeapFree(GetProcessHeap(), 0, buffer); @@ -4757,16 +5800,22 @@ static void test_events(int useMessages) /* broken on all windows - FD_CONNECT error is garbage */ /* Test simple send/recv */ + SetLastError(0xdeadbeef); ret = send(dst, buffer, 100, 0); ok(ret == 100, "Failed to send buffer %d err %d\n", ret, GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok_event_seq(src, hEvent, read_seq, NULL, 0); + SetLastError(0xdeadbeef); ret = recv(src, buffer, 1, MSG_PEEK); ok(ret == 1, "Failed to peek at recv buffer %d err %d\n", ret, GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok_event_seq(src, hEvent, read_seq, NULL, 0); + SetLastError(0xdeadbeef); ret = recv(src, buffer, 50, 0); ok(ret == 50, "Failed to recv buffer %d err %d\n", ret, GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok_event_seq(src, hEvent, read_seq, NULL, 0); ret = recv(src, buffer, 50, 0); @@ -4790,8 +5839,10 @@ static void test_events(int useMessages) else ok_event_seq(src, hEvent, empty_seq, NULL, 0); + SetLastError(0xdeadbeef); ret = recv(src, buffer, 1, 0); ok(ret == 1, "Failed to recv buffer %d err %d\n", ret, GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok_event_seq(src, hEvent, empty_seq, NULL, 0); /* Interaction with overlapped */ @@ -4833,8 +5884,10 @@ static void test_events(int useMessages) ok(buffer[1] == '2', "Got %c instead of 2\n", buffer[1]); } + SetLastError(0xdeadbeef); ret = send(dst, "1", 1, 0); ok(ret == 1, "Failed to send buffer %d err %d\n", ret, GetLastError()); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok_event_seq(src, hEvent, read_seq, NULL, 0); ret = recv(src, buffer, 1, 0); @@ -5205,17 +6258,22 @@ static void test_WSASendMsg(void) set_blocking(sock, TRUE); bytesSent = 0; + SetLastError(0xdeadbeef); ret = pWSASendMsg(sock, &msg, 0, &bytesSent, NULL, NULL); ok(!ret, "WSASendMsg should have worked\n"); + ok(GetLastError() == 0 || broken(GetLastError() == 0xdeadbeef) /* Win <= 2008 */, + "Expected 0, got %d\n", GetLastError()); ok(bytesSent == iovec[0].len, "incorret bytes sent, expected %d, sent %d\n", iovec[0].len, bytesSent); /* receive data */ addrlen = sizeof(sockaddr); memset(buffer, 0, sizeof(buffer)); + SetLastError(0xdeadbeef); ret = recvfrom(dst, buffer, sizeof(buffer), 0, (struct sockaddr *) &sockaddr, &addrlen); ok(ret == bytesSent, "got %d, expected %d\n", ret, bytesSent); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); /* A successful call to WSASendMsg must have bound the socket */ addrlen = sizeof(sockaddr); @@ -5230,17 +6288,22 @@ static void test_WSASendMsg(void) msg.dwBufferCount = 2; /* send both buffers */ bytesSent = 0; + SetLastError(0xdeadbeef); ret = pWSASendMsg(sock, &msg, 0, &bytesSent, NULL, NULL); ok(!ret, "WSASendMsg should have worked\n"); ok(bytesSent == iovec[0].len + iovec[1].len, "incorret bytes sent, expected %d, sent %d\n", iovec[0].len + iovec[1].len, bytesSent); + ok(GetLastError() == 0 || broken(GetLastError() == 0xdeadbeef) /* Win <= 2008 */, + "Expected 0, got %d\n", GetLastError()); /* receive data */ addrlen = sizeof(sockaddr); memset(buffer, 0, sizeof(buffer)); + SetLastError(0xdeadbeef); ret = recvfrom(dst, buffer, sizeof(buffer), 0, (struct sockaddr *) &sockaddr, &addrlen); ok(ret == bytesSent, "got %d, expected %d\n", ret, bytesSent); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); closesocket(sock); closesocket(dst); @@ -5353,8 +6416,6 @@ static void test_WSARecv(void) BOOL bret; HANDLE thread; - memset(&ov, 0, sizeof(ov)); - tcp_socketpair(&src, &dest); if (src == INVALID_SOCKET || dest == INVALID_SOCKET) { @@ -5362,9 +6423,42 @@ static void test_WSARecv(void) goto end; } - bufs.len = sizeof(buf); - bufs.buf = buf; + memset(&ov, 0, sizeof(ov)); flags = 0; + bufs.len = 2; + bufs.buf = buf; + + /* Send 4 bytes and receive in two calls of 2 */ + SetLastError(0xdeadbeef); + iret = send(src, "test", 4, 0); + ok(iret == 4, "Expected 4, got %d\n", iret); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + bytesReturned = 0xdeadbeef; + iret = WSARecv(dest, &bufs, 1, &bytesReturned, &flags, NULL, NULL); + ok(!iret, "Expected 0, got %d\n", iret); + ok(bytesReturned, "Expected 2, got %d\n", bytesReturned); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + bytesReturned = 0xdeadbeef; + iret = WSARecv(dest, &bufs, 1, &bytesReturned, &flags, NULL, NULL); + ok(!iret, "Expected 0, got %d\n", iret); + ok(bytesReturned, "Expected 2, got %d\n", bytesReturned); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); + + bufs.len = 4; + SetLastError(0xdeadbeef); + iret = send(src, "test", 4, 0); + ok(iret == 4, "Expected 4, got %d\n", iret); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); + SetLastError(0xdeadbeef); + bytesReturned = 0xdeadbeef; + iret = WSARecv(dest, &bufs, 1, &bytesReturned, &flags, NULL, NULL); + ok(!iret, "Expected 0, got %d\n", iret); + ok(bytesReturned, "Expected 4, got %d\n", bytesReturned); + ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); + + bufs.len = sizeof(buf); ov.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL); ok(ov.hEvent != NULL, "could not create event object, errno = %d\n", GetLastError()); @@ -5426,6 +6520,7 @@ static void test_WSARecv(void) send(src, "test message", sizeof("test message"), 0); thread = CreateThread(NULL, 0, recv_thread, &dest, 0, &id); + WaitForSingleObject(thread, 3000); CloseHandle(thread); end: @@ -5439,6 +6534,229 @@ 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; + err = getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char*)&id, &len); + ok(!err, "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); +todo_wine + 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); +todo_wine + ok(ret == 0, "expected 0, got %d\n", ret); + len = sizeof(id); + id = 0xdeadbeef; + err = getsockopt(fdWrite, SOL_SOCKET, SO_ERROR, (char*)&id, &len); + ok(!err, "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); +todo_wine + 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); +todo_wine + 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}; @@ -5449,6 +6767,8 @@ static void test_GetAddrInfoW(void) static const WCHAR zero[] = {'0',0}; int i, ret; ADDRINFOW *result, *result2, *p, hint; + WCHAR name[256]; + DWORD size = sizeof(name)/sizeof(WCHAR); if (!pGetAddrInfoW || !pFreeAddrInfoW) { @@ -5456,16 +6776,22 @@ static void test_GetAddrInfoW(void) return; } memset(&hint, 0, sizeof(ADDRINFOW)); + name[0] = 0; + GetComputerNameExW( ComputerNamePhysicalDnsHostname, name, &size ); result = (ADDRINFOW *)0xdeadbeef; + WSASetLastError(0xdeadbeef); ret = pGetAddrInfoW(NULL, NULL, NULL, &result); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); + ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = NULL; + WSASetLastError(0xdeadbeef); ret = pGetAddrInfoW(empty, NULL, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); + ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); pFreeAddrInfoW(result); result = NULL; @@ -5484,6 +6810,7 @@ static void test_GetAddrInfoW(void) result = NULL; ret = pGetAddrInfoW(empty, zero, NULL, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); ok(result != NULL, "GetAddrInfoW failed\n"); result2 = NULL; @@ -5520,11 +6847,38 @@ static void test_GetAddrInfoW(void) pFreeAddrInfoW(result); result = NULL; + SetLastError(0xdeadbeef); ret = pGetAddrInfoW(localhost, port, &hint, &result); ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); + pFreeAddrInfoW(result); + + /* try to get information from the computer name, result is the same + * as if requesting with an empty host name. */ + ret = pGetAddrInfoW(name, NULL, NULL, &result); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + + ret = pGetAddrInfoW(empty, NULL, NULL, &result2); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result2 != NULL, "GetAddrInfoW failed\n"); + compare_addrinfow(result, result2); pFreeAddrInfoW(result); + pFreeAddrInfoW(result2); + + ret = pGetAddrInfoW(name, empty, NULL, &result); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result != NULL, "GetAddrInfoW failed\n"); + + ret = pGetAddrInfoW(empty, empty, NULL, &result2); + ok(!ret, "GetAddrInfoW failed with %d\n", WSAGetLastError()); + ok(result2 != NULL, "GetAddrInfoW failed\n"); + compare_addrinfow(result, result2); + pFreeAddrInfoW(result); + pFreeAddrInfoW(result2); result = (ADDRINFOW *)0xdeadbeef; + WSASetLastError(0xdeadbeef); ret = pGetAddrInfoW(NULL, NULL, NULL, &result); if(ret == 0) { @@ -5532,9 +6886,11 @@ static void test_GetAddrInfoW(void) return; } ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); + ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = (ADDRINFOW *)0xdeadbeef; + WSASetLastError(0xdeadbeef); ret = pGetAddrInfoW(nxdomain, NULL, NULL, &result); if(ret == 0) { @@ -5542,6 +6898,7 @@ static void test_GetAddrInfoW(void) return; } ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); + ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); for (i = 0;i < (sizeof(hinttests) / sizeof(hinttests[0]));i++) @@ -5600,6 +6957,8 @@ static void test_getaddrinfo(void) { int i, ret; ADDRINFOA *result, *result2, *p, hint; + CHAR name[256]; + DWORD size = sizeof(name); if (!pgetaddrinfo || !pfreeaddrinfo) { @@ -5607,16 +6966,21 @@ static void test_getaddrinfo(void) return; } memset(&hint, 0, sizeof(ADDRINFOA)); + GetComputerNameExA( ComputerNamePhysicalDnsHostname, name, &size ); result = (ADDRINFOA *)0xdeadbeef; + WSASetLastError(0xdeadbeef); ret = pgetaddrinfo(NULL, NULL, NULL, &result); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); + ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); result = NULL; + WSASetLastError(0xdeadbeef); ret = pgetaddrinfo("", NULL, NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); ok(result != NULL, "getaddrinfo failed\n"); + ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); pfreeaddrinfo(result); result = NULL; @@ -5633,8 +6997,10 @@ static void test_getaddrinfo(void) pfreeaddrinfo(result2); result = NULL; + WSASetLastError(0xdeadbeef); ret = pgetaddrinfo("", "0", NULL, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); ok(result != NULL, "getaddrinfo failed\n"); result2 = NULL; @@ -5671,11 +7037,38 @@ static void test_getaddrinfo(void) pfreeaddrinfo(result); result = NULL; + WSASetLastError(0xdeadbeef); ret = pgetaddrinfo("localhost", "80", &hint, &result); ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(WSAGetLastError() == 0, "expected 0, got %d\n", WSAGetLastError()); + pfreeaddrinfo(result); + + /* try to get information from the computer name, result is the same + * as if requesting with an empty host name. */ + ret = pgetaddrinfo(name, NULL, NULL, &result); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result != NULL, "getaddrinfo failed\n"); + + ret = pgetaddrinfo("", NULL, NULL, &result2); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result2 != NULL, "getaddrinfo failed\n"); + compare_addrinfo(result, result2); + pfreeaddrinfo(result); + pfreeaddrinfo(result2); + + ret = pgetaddrinfo(name, "", NULL, &result); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result != NULL, "getaddrinfo failed\n"); + + ret = pgetaddrinfo("", "", NULL, &result2); + ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError()); + ok(result2 != NULL, "getaddrinfo failed\n"); + compare_addrinfo(result, result2); pfreeaddrinfo(result); + pfreeaddrinfo(result2); result = (ADDRINFOA *)0xdeadbeef; + WSASetLastError(0xdeadbeef); ret = pgetaddrinfo("nxdomain.codeweavers.com", NULL, NULL, &result); if(ret == 0) { @@ -5683,6 +7076,7 @@ static void test_getaddrinfo(void) return; } ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); + ok(WSAGetLastError() == WSAHOST_NOT_FOUND, "expected 11001, got %d\n", WSAGetLastError()); ok(result == NULL, "got %p\n", result); for (i = 0;i < (sizeof(hinttests) / sizeof(hinttests[0]));i++) @@ -6462,6 +7856,361 @@ end: closesocket(connector2); } +static void test_DisconnectEx(void) +{ + SOCKET listener, acceptor, connector; + LPFN_DISCONNECTEX pDisconnectEx; + GUID disconnectExGuid = WSAID_DISCONNECTEX; + struct sockaddr_in address; + DWORD num_bytes, flags; + OVERLAPPED overlapped; + int addrlen, iret; + BOOL bret; + + connector = socket(AF_INET, SOCK_STREAM, 0); + ok(connector != INVALID_SOCKET, "failed to create connector socket, error %d\n", WSAGetLastError()); + + iret = WSAIoctl(connector, SIO_GET_EXTENSION_FUNCTION_POINTER, &disconnectExGuid, sizeof(disconnectExGuid), + &pDisconnectEx, sizeof(pDisconnectEx), &num_bytes, NULL, NULL); + if (iret) + { + win_skip("WSAIoctl failed to get DisconnectEx, error %d\n", WSAGetLastError()); + closesocket(connector); + return; + } + + listener = socket(AF_INET, SOCK_STREAM, 0); + ok(listener != INVALID_SOCKET, "failed to create listener socket, error %d\n", WSAGetLastError()); + + memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr("127.0.0.1"); + iret = bind(listener, (struct sockaddr *)&address, sizeof(address)); + ok(iret == 0, "failed to bind, error %d\n", WSAGetLastError()); + + addrlen = sizeof(address); + iret = getsockname(listener, (struct sockaddr *)&address, &addrlen); + ok(iret == 0, "failed to lookup bind address, error %d\n", WSAGetLastError()); + + iret = listen(listener, 1); + ok(iret == 0, "failed to listen, error %d\n", WSAGetLastError()); + + set_blocking(listener, TRUE); + + memset(&overlapped, 0, sizeof(overlapped)); + bret = pDisconnectEx(INVALID_SOCKET, &overlapped, 0, 0); + ok(bret == FALSE, "DisconnectEx unexpectedly succeeded\n"); + ok(WSAGetLastError() == WSAENOTSOCK, "expected WSAENOTSOCK, got %d\n", WSAGetLastError()); + + memset(&overlapped, 0, sizeof(overlapped)); + bret = pDisconnectEx(connector, &overlapped, 0, 0); + ok(bret == FALSE, "DisconnectEx unexpectedly succeeded\n"); + todo_wine ok(WSAGetLastError() == WSAENOTCONN, "expected WSAENOTCONN, got %d\n", WSAGetLastError()); + + iret = connect(connector, (struct sockaddr *)&address, addrlen); + ok(iret == 0, "failed to connect, error %d\n", WSAGetLastError()); + + acceptor = accept(listener, NULL, NULL); + ok(acceptor != INVALID_SOCKET, "could not accept socket, error %d\n", WSAGetLastError()); + + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = WSACreateEvent(); + ok(overlapped.hEvent != WSA_INVALID_EVENT, "WSACreateEvent failed, error %d\n", WSAGetLastError()); + bret = pDisconnectEx(connector, &overlapped, 0, 0); + if (bret) + ok(overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %08lx\n", overlapped.Internal); + else if (WSAGetLastError() == ERROR_IO_PENDING) + bret = WSAGetOverlappedResult(connector, &overlapped, &num_bytes, TRUE, &flags); + ok(bret, "DisconnectEx failed, error %d\n", WSAGetLastError()); + WSACloseEvent(overlapped.hEvent); + + iret = connect(connector, (struct sockaddr *)&address, sizeof(address)); + ok(iret != 0, "connect unexpectedly succeeded\n"); + ok(WSAGetLastError() == WSAEISCONN, "expected WSAEISCONN, got %d\n", WSAGetLastError()); + + closesocket(acceptor); + closesocket(connector); + + connector = socket(AF_INET, SOCK_STREAM, 0); + ok(connector != INVALID_SOCKET, "failed to create connector socket, error %d\n", WSAGetLastError()); + + iret = connect(connector, (struct sockaddr *)&address, addrlen); + ok(iret == 0, "failed to connect, error %d\n", WSAGetLastError()); + + acceptor = accept(listener, NULL, NULL); + ok(acceptor != INVALID_SOCKET, "could not accept socket, error %d\n", WSAGetLastError()); + + bret = pDisconnectEx(connector, NULL, 0, 0); + ok(bret, "DisconnectEx failed, error %d\n", WSAGetLastError()); + + iret = connect(connector, (struct sockaddr *)&address, sizeof(address)); + ok(iret != 0, "connect unexpectedly succeeded\n"); + ok(WSAGetLastError() == WSAEISCONN, "expected WSAEISCONN, got %d\n", WSAGetLastError()); + + closesocket(acceptor); + closesocket(connector); + closesocket(listener); +} + +#define compare_file(h,s,o) compare_file2(h,s,o,__FILE__,__LINE__) + +static void compare_file2(HANDLE handle, SOCKET sock, int offset, const char *file, int line) +{ + char buf1[256], buf2[256]; + BOOL success; + int i = 0; + + SetFilePointer(handle, offset, NULL, FILE_BEGIN); + while (1) + { + DWORD n1 = 0, n2 = 0; + + success = ReadFile(handle, buf1, sizeof(buf1), &n1, NULL); + ok_(file,line)(success, "Failed to read from file.\n"); + if (success && n1 == 0) + break; + else if(!success) + return; + n2 = recv(sock, buf2, n1, 0); + ok_(file,line)(n1 == n2, "Block %d size mismatch (%d != %d)\n", i, n1, n2); + ok_(file,line)(memcmp(buf1, buf2, n2) == 0, "Block %d failed\n", i); + i++; + } +} + +static void test_TransmitFile(void) +{ + DWORD num_bytes, err, file_size, total_sent; + GUID transmitFileGuid = WSAID_TRANSMITFILE; + LPFN_TRANSMITFILE pTransmitFile = NULL; + HANDLE file = INVALID_HANDLE_VALUE; + char header_msg[] = "hello world"; + char footer_msg[] = "goodbye!!!"; + char system_ini_path[MAX_PATH]; + struct sockaddr_in bindAddress; + TRANSMIT_FILE_BUFFERS buffers; + SOCKET client, server, dest; + WSAOVERLAPPED ov; + char buf[256]; + int iret, len; + BOOL bret; + + memset( &ov, 0, sizeof(ov) ); + + /* Setup sockets for testing TransmitFile */ + client = socket(AF_INET, SOCK_STREAM, 0); + server = socket(AF_INET, SOCK_STREAM, 0); + if (client == INVALID_SOCKET || server == INVALID_SOCKET) + { + skip("could not create acceptor socket, error %d\n", WSAGetLastError()); + goto cleanup; + } + iret = WSAIoctl(client, SIO_GET_EXTENSION_FUNCTION_POINTER, &transmitFileGuid, sizeof(transmitFileGuid), + &pTransmitFile, sizeof(pTransmitFile), &num_bytes, NULL, NULL); + if (iret) + { + skip("WSAIoctl failed to get TransmitFile with ret %d + errno %d\n", iret, WSAGetLastError()); + goto cleanup; + } + GetSystemWindowsDirectoryA(system_ini_path, MAX_PATH ); + strcat(system_ini_path, "\\system.ini"); + file = CreateFileA(system_ini_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0x0, NULL); + if (file == INVALID_HANDLE_VALUE) + { + skip("Unable to open a file to transmit.\n"); + goto cleanup; + } + file_size = GetFileSize(file, NULL); + + /* Test TransmitFile with an invalid socket */ + bret = pTransmitFile(INVALID_SOCKET, file, 0, 0, NULL, NULL, 0); + err = WSAGetLastError(); + ok(!bret, "TransmitFile succeeded unexpectedly.\n"); + ok(err == WSAENOTSOCK, "TransmitFile triggered unexpected errno (%d != %d)\n", err, WSAENOTSOCK); + + /* Test a bogus TransmitFile without a connected socket */ + bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, TF_REUSE_SOCKET); + err = WSAGetLastError(); + ok(!bret, "TransmitFile succeeded unexpectedly.\n"); + ok(err == WSAENOTCONN, "TransmitFile triggered unexpected errno (%d != %d)\n", err, WSAENOTCONN); + + /* Setup a properly connected socket for transfers */ + memset(&bindAddress, 0, sizeof(bindAddress)); + bindAddress.sin_family = AF_INET; + bindAddress.sin_port = htons(9375); + bindAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); + iret = bind(server, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); + if (iret != 0) + { + skip("failed to bind(), error %d\n", WSAGetLastError()); + goto cleanup; + } + iret = listen(server, 1); + if (iret != 0) + { + skip("failed to listen(), error %d\n", WSAGetLastError()); + goto cleanup; + } + iret = connect(client, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); + if (iret != 0) + { + skip("failed to connect(), error %d\n", WSAGetLastError()); + goto cleanup; + } + len = sizeof(bindAddress); + dest = accept(server, (struct sockaddr*)&bindAddress, &len); + if (dest == INVALID_SOCKET) + { + skip("failed to accept(), error %d\n", WSAGetLastError()); + goto cleanup; + } + if (set_blocking(dest, FALSE)) + { + skip("couldn't make socket non-blocking, error %d\n", WSAGetLastError()); + goto cleanup; + } + + /* Test TransmitFile with no possible buffer */ + bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0); + ok(bret, "TransmitFile failed unexpectedly.\n"); + iret = recv(dest, buf, sizeof(buf), 0); + ok(iret == -1, "Returned an unexpected buffer from TransmitFile (%d != -1).\n", iret); + + /* Test TransmitFile with only buffer data */ + buffers.Head = &header_msg[0]; + buffers.HeadLength = sizeof(header_msg)+1; + buffers.Tail = &footer_msg[0]; + buffers.TailLength = sizeof(footer_msg)+1; + bret = pTransmitFile(client, NULL, 0, 0, NULL, &buffers, 0); + ok(bret, "TransmitFile failed unexpectedly.\n"); + iret = recv(dest, buf, sizeof(buf), 0); + ok(iret == sizeof(header_msg)+sizeof(footer_msg)+2, + "Returned an unexpected buffer from TransmitFile: %d\n", iret ); + ok(memcmp(&buf[0], &header_msg[0], sizeof(header_msg)+1) == 0, + "TransmitFile header buffer did not match!\n"); + ok(memcmp(&buf[sizeof(header_msg)+1], &footer_msg[0], sizeof(footer_msg)+1) == 0, + "TransmitFile footer buffer did not match!\n"); + + /* Test TransmitFile with only file data */ + bret = pTransmitFile(client, file, 0, 0, NULL, NULL, 0); + ok(bret, "TransmitFile failed unexpectedly.\n"); + compare_file(file, dest, 0); + + /* Test TransmitFile with both file and buffer data */ + buffers.Head = &header_msg[0]; + buffers.HeadLength = sizeof(header_msg)+1; + buffers.Tail = &footer_msg[0]; + buffers.TailLength = sizeof(footer_msg)+1; + SetFilePointer(file, 0, NULL, FILE_BEGIN); + bret = pTransmitFile(client, file, 0, 0, NULL, &buffers, 0); + ok(bret, "TransmitFile failed unexpectedly.\n"); + iret = recv(dest, buf, sizeof(header_msg)+1, 0); + ok(memcmp(buf, &header_msg[0], sizeof(header_msg)+1) == 0, + "TransmitFile header buffer did not match!\n"); + compare_file(file, dest, 0); + iret = recv(dest, buf, sizeof(footer_msg)+1, 0); + ok(memcmp(buf, &footer_msg[0], sizeof(footer_msg)+1) == 0, + "TransmitFile footer buffer did not match!\n"); + + /* Test overlapped TransmitFile */ + ov.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (ov.hEvent == INVALID_HANDLE_VALUE) + { + skip("Could not create event object, some tests will be skipped. errno = %d\n", + GetLastError()); + goto cleanup; + } + SetFilePointer(file, 0, NULL, FILE_BEGIN); + bret = pTransmitFile(client, file, 0, 0, &ov, NULL, 0); + err = WSAGetLastError(); + ok(!bret, "TransmitFile succeeded unexpectedly.\n"); + ok(err == ERROR_IO_PENDING, "TransmitFile triggered unexpected errno (%d != %d)\n", + err, ERROR_IO_PENDING); + iret = WaitForSingleObject(ov.hEvent, 2000); + ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); + WSAGetOverlappedResult(client, &ov, &total_sent, FALSE, NULL); + ok(total_sent == file_size, + "Overlapped TransmitFile sent an unexpected number of bytes (%d != %d).\n", + total_sent, file_size); + compare_file(file, dest, 0); + + /* Test overlapped TransmitFile w/ start offset */ + ov.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (ov.hEvent == INVALID_HANDLE_VALUE) + { + skip("Could not create event object, some tests will be skipped. errno = %d\n", GetLastError()); + goto cleanup; + } + SetFilePointer(file, 0, NULL, FILE_BEGIN); + ov.Offset = 10; + bret = pTransmitFile(client, file, 0, 0, &ov, NULL, 0); + err = WSAGetLastError(); + ok(!bret, "TransmitFile succeeded unexpectedly.\n"); + ok(err == ERROR_IO_PENDING, "TransmitFile triggered unexpected errno (%d != %d)\n", err, ERROR_IO_PENDING); + iret = WaitForSingleObject(ov.hEvent, 2000); + ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); + WSAGetOverlappedResult(client, &ov, &total_sent, FALSE, NULL); + ok(total_sent == (file_size - ov.Offset), + "Overlapped TransmitFile sent an unexpected number of bytes (%d != %d).\n", + total_sent, file_size - ov.Offset); + compare_file(file, dest, ov.Offset); + + /* Test overlapped TransmitFile w/ file and buffer data */ + ov.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + if (ov.hEvent == INVALID_HANDLE_VALUE) + { + skip("Could not create event object, some tests will be skipped. errno = %d\n", GetLastError()); + goto cleanup; + } + buffers.Head = &header_msg[0]; + buffers.HeadLength = sizeof(header_msg)+1; + buffers.Tail = &footer_msg[0]; + buffers.TailLength = sizeof(footer_msg)+1; + SetFilePointer(file, 0, NULL, FILE_BEGIN); + ov.Offset = 0; + bret = pTransmitFile(client, file, 0, 0, &ov, &buffers, 0); + err = WSAGetLastError(); + ok(!bret, "TransmitFile succeeded unexpectedly.\n"); + ok(err == ERROR_IO_PENDING, "TransmitFile triggered unexpected errno (%d != %d)\n", err, ERROR_IO_PENDING); + iret = WaitForSingleObject(ov.hEvent, 2000); + ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); + WSAGetOverlappedResult(client, &ov, &total_sent, FALSE, NULL); + ok(total_sent == (file_size + buffers.HeadLength + buffers.TailLength), + "Overlapped TransmitFile sent an unexpected number of bytes (%d != %d).\n", + total_sent, file_size + buffers.HeadLength + buffers.TailLength); + iret = recv(dest, buf, sizeof(header_msg)+1, 0); + ok(memcmp(buf, &header_msg[0], sizeof(header_msg)+1) == 0, + "TransmitFile header buffer did not match!\n"); + compare_file(file, dest, 0); + iret = recv(dest, buf, sizeof(footer_msg)+1, 0); + ok(memcmp(buf, &footer_msg[0], sizeof(footer_msg)+1) == 0, + "TransmitFile footer buffer did not match!\n"); + + /* Test TransmitFile w/ TF_DISCONNECT */ + SetFilePointer(file, 0, NULL, FILE_BEGIN); + bret = pTransmitFile(client, file, 0, 0, NULL, NULL, TF_DISCONNECT); + ok(bret, "TransmitFile failed unexpectedly.\n"); + compare_file(file, dest, 0); + closesocket(client); + ok(send(client, "test", 4, 0) == -1, "send() after TF_DISCONNECT succeeded unexpectedly.\n"); + err = WSAGetLastError(); + todo_wine ok(err == WSAENOTSOCK, "send() after TF_DISCONNECT triggered unexpected errno (%d != %d)\n", + err, WSAENOTSOCK); + + /* Test TransmitFile with a UDP datagram socket */ + client = socket(AF_INET, SOCK_DGRAM, 0); + bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0); + err = WSAGetLastError(); + ok(!bret, "TransmitFile succeeded unexpectedly.\n"); + ok(err == WSAENOTCONN, "TransmitFile triggered unexpected errno (%d != %d)\n", err, WSAENOTCONN); + +cleanup: + CloseHandle(file); + CloseHandle(ov.hEvent); + closesocket(client); + closesocket(server); +} + static void test_getpeername(void) { SOCKET sock; @@ -6615,6 +8364,73 @@ static void test_sioRoutingInterfaceQuery(void) closesocket(sock); } +static void test_sioAddressListChange(void) +{ + struct sockaddr_in bindAddress; + struct in_addr net_address; + WSAOVERLAPPED overlapped; + struct hostent *h; + DWORD num_bytes; + SOCKET sock; + int acount; + int ret; + + if (!winetest_interactive) + { + skip("Cannot test SIO_ADDRESS_LIST_CHANGE, interactive tests must be enabled\n"); + return; + } + + /* Use gethostbyname to find the list of local network interfaces */ + h = gethostbyname(""); + if (!h) + { + skip("Cannot test SIO_ADDRESS_LIST_CHANGE, gethostbyname failed with %u\n", + WSAGetLastError()); + return; + } + for (acount = 0; h->h_addr_list[acount]; acount++); + if (acount == 0) + { + skip("Cannot test SIO_ADDRESS_LIST_CHANGE, test requires a network card.\n"); + return; + } + net_address.s_addr = *(ULONG *) h->h_addr_list[0]; + + /* 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; + 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; + } + + /* 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()); + 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); + ok(ret == WAIT_OBJECT_0, "failed to get overlapped event %u\n", ret); + +end: + closesocket(sock); +} + static void test_synchronous_WSAIoctl(void) { HANDLE previous_port, io_port; @@ -6805,6 +8621,7 @@ static void test_completion_port(void) GUID acceptExGuid = WSAID_ACCEPTEX; LPFN_ACCEPTEX pAcceptEx = NULL; + memset(buf, 0, sizeof(buf)); previous_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); ok( previous_port != NULL, "Failed to create completion port %u\n", GetLastError()); @@ -7432,6 +9249,69 @@ static void test_completion_port(void) CloseHandle(previous_port); } +static void test_address_list_query(void) +{ + SOCKET_ADDRESS_LIST *address_list; + DWORD bytes_returned, size; + unsigned int i; + SOCKET s; + int ret; + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(s != INVALID_SOCKET, "Failed to create socket, error %d.\n", WSAGetLastError()); + + bytes_returned = 0; + ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &bytes_returned, NULL, NULL); + ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); + if(WSAGetLastError() == WSAEINVAL) + { + win_skip("Windows <= NT4 is not supported in this test\n"); + closesocket(s); + return; + } + ok(WSAGetLastError() == WSAEFAULT, "Got unexpected error %d.\n", WSAGetLastError()); + ok(bytes_returned >= FIELD_OFFSET(SOCKET_ADDRESS_LIST, Address[0]), + "Got unexpected bytes_returned %u.\n", bytes_returned); + + size = bytes_returned; + bytes_returned = 0; + address_list = HeapAlloc(GetProcessHeap(), 0, size * 2); + ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, address_list, size * 2, &bytes_returned, NULL, NULL); + ok(!ret, "Got unexpected ret %d, error %d.\n", ret, WSAGetLastError()); + ok(bytes_returned == size, "Got unexpected bytes_returned %u, expected %u.\n", bytes_returned, size); + + bytes_returned = FIELD_OFFSET(SOCKET_ADDRESS_LIST, Address[address_list->iAddressCount]); + for (i = 0; i < address_list->iAddressCount; ++i) + { + bytes_returned += address_list->Address[i].iSockaddrLength; + } + ok(size == bytes_returned, "Got unexpected size %u, expected %u.\n", size, bytes_returned); + + ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, address_list, size, NULL, NULL, NULL); + ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); + ok(WSAGetLastError() == WSAEFAULT, "Got unexpected error %d.\n", WSAGetLastError()); + + bytes_returned = 0xdeadbeef; + ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, size, &bytes_returned, NULL, NULL); + ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); + ok(WSAGetLastError() == WSAEFAULT, "Got unexpected error %d.\n", WSAGetLastError()); + ok(bytes_returned == size, "Got unexpected bytes_returned %u, expected %u.\n", bytes_returned, size); + + ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, address_list, 1, &bytes_returned, NULL, NULL); + ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); + ok(WSAGetLastError() == WSAEINVAL, "Got unexpected error %d.\n", WSAGetLastError()); + ok(bytes_returned == 0, "Got unexpected bytes_returned %u.\n", bytes_returned); + + ret = WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0, address_list, + FIELD_OFFSET(SOCKET_ADDRESS_LIST, Address[0]), &bytes_returned, NULL, NULL); + ok(ret == SOCKET_ERROR, "Got unexpected ret %d.\n", ret); + ok(WSAGetLastError() == WSAEFAULT, "Got unexpected error %d.\n", WSAGetLastError()); + ok(bytes_returned == size, "Got unexpected bytes_returned %u, expected %u.\n", bytes_returned, size); + + HeapFree(GetProcessHeap(), 0, address_list); + closesocket(s); +} + static DWORD WINAPI inet_ntoa_thread_proc(void *param) { ULONG addr; @@ -7638,6 +9518,176 @@ todo_wine ok(!ret, "WSALookupServiceEnd failed unexpectedly\n"); } +static void test_WSAEnumNameSpaceProvidersA(void) +{ + LPWSANAMESPACE_INFOA name = NULL; + DWORD ret, error, blen = 0, i; + if (!pWSAEnumNameSpaceProvidersA) + { + win_skip("WSAEnumNameSpaceProvidersA not found\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersA(&blen, name); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + + /* Invalid parameter tests */ + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersA(NULL, name); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersA(NULL, NULL); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersA(&blen, NULL); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + +#ifdef __REACTOS__ /* ROSTESTS-233 */ + if (!blen) + { + skip("Failed to get length needed for name space providers.\n"); + return; + } +#endif + + name = HeapAlloc(GetProcessHeap(), 0, blen); + if (!name) + { + skip("Failed to alloc memory\n"); + return; + } + + ret = pWSAEnumNameSpaceProvidersA(&blen, name); +todo_wine + ok(ret > 0, "Expected more than zero name space providers\n"); + + for (i = 0;i < ret; i++) + { + trace("Name space Identifier (%p): %s\n", name[i].lpszIdentifier, + name[i].lpszIdentifier); + switch (name[i].dwNameSpace) + { + case NS_DNS: + trace("\tName space ID: NS_DNS (%u)\n", name[i].dwNameSpace); + break; + case NS_NLA: + trace("\tName space ID: NS_NLA (%u)\n", name[i].dwNameSpace); + break; + default: + trace("\tName space ID: Unknown (%u)\n", name[i].dwNameSpace); + break; + } + trace("\tActive: %d\n", name[i].fActive); + trace("\tVersion: %d\n", name[i].dwVersion); + } + + HeapFree(GetProcessHeap(), 0, name); +} + +static void test_WSAEnumNameSpaceProvidersW(void) +{ + LPWSANAMESPACE_INFOW name = NULL; + DWORD ret, error, blen = 0, i; + if (!pWSAEnumNameSpaceProvidersW) + { + win_skip("WSAEnumNameSpaceProvidersW not found\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersW(&blen, name); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + + /* Invalid parameter tests */ + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersW(NULL, name); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersW(NULL, NULL); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + + SetLastError(0xdeadbeef); + ret = pWSAEnumNameSpaceProvidersW(&blen, NULL); + error = WSAGetLastError(); +todo_wine + ok(ret == SOCKET_ERROR, "Expected failure, got %u\n", ret); +todo_wine + ok(error == WSAEFAULT, "Expected 10014, got %u\n", error); + +#ifdef __REACTOS__ /* ROSTESTS-233 */ + if (!blen) + { + skip("Failed to get length needed for name space providers.\n"); + return; + } +#endif + + name = HeapAlloc(GetProcessHeap(), 0, blen); + if (!name) + { + skip("Failed to alloc memory\n"); + return; + } + + ret = pWSAEnumNameSpaceProvidersW(&blen, name); +todo_wine + ok(ret > 0, "Expected more than zero name space providers\n"); + + for (i = 0;i < ret; i++) + { + trace("Name space Identifier (%p): %s\n", name[i].lpszIdentifier, + wine_dbgstr_w(name[i].lpszIdentifier)); + switch (name[i].dwNameSpace) + { + case NS_DNS: + trace("\tName space ID: NS_DNS (%u)\n", name[i].dwNameSpace); + break; + case NS_NLA: + trace("\tName space ID: NS_NLA (%u)\n", name[i].dwNameSpace); + break; + default: + trace("\tName space ID: Unknown (%u)\n", name[i].dwNameSpace); + break; + } + trace("\tActive: %d\n", name[i].fActive); + trace("\tVersion: %d\n", name[i].dwVersion); + } + + HeapFree(GetProcessHeap(), 0, name); +} + /**************** Main program ***************/ START_TEST( sock ) @@ -7652,6 +9702,7 @@ START_TEST( sock ) Init(); test_inet_ntoa(); + test_inet_pton(); test_set_getsockopt(); test_so_reuseaddr(); test_ip_pktinfo(); @@ -7669,6 +9720,7 @@ START_TEST( sock ) test_getservbyname(); test_WSASocket(); test_WSADuplicateSocket(); + test_WSAEnumNetworkEvents(); test_WSAAddressToStringA(); test_WSAAddressToStringW(); @@ -7686,29 +9738,38 @@ START_TEST( sock ) test_addr_to_print(); test_ioctlsocket(); test_dns(); + test_gethostbyname(); test_gethostbyname_hack(); + test_gethostname(); test_WSASendMsg(); test_WSASendTo(); test_WSARecv(); + test_WSAPoll(); test_events(0); test_events(1); test_ipv6only(); + test_TransmitFile(); test_GetAddrInfoW(); test_getaddrinfo(); test_AcceptEx(); test_ConnectEx(); + test_DisconnectEx(); test_sioRoutingInterfaceQuery(); + test_sioAddressListChange(); test_WSALookupService(); + test_WSAEnumNameSpaceProvidersA(); + test_WSAEnumNameSpaceProvidersW(); test_WSAAsyncGetServByPort(); test_WSAAsyncGetServByName(); test_completion_port(); + test_address_list_query(); /* this is an io heavy test, do it at the end so the kernel doesn't start dropping packets */ test_send(); -- 2.17.1