diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index d688994e629..a5df51d4217 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -154,6 +154,7 @@ #include "winnt.h" #define USE_WC_PREFIX /* For CMSG_DATA */ #include "iphlpapi.h" +#include "ip2string.h" #include "wine/server.h" #include "wine/debug.h" #include "wine/exception.h" @@ -8484,7 +8485,7 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString, LPINT lpAddressLength) { INT res=0; - LPSTR workBuffer=NULL,ptrPort; + NTSTATUS status; TRACE( "(%s, %x, %p, %p, %p)\n", debugstr_a(AddressString), AddressFamily, lpProtocolInfo, lpAddress, lpAddressLength ); @@ -8500,21 +8501,11 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString, if (lpProtocolInfo) FIXME("ProtocolInfo not implemented.\n"); - workBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - strlen(AddressString) + 1); - if (!workBuffer) - { - SetLastError(WSA_NOT_ENOUGH_MEMORY); - return SOCKET_ERROR; - } - - strcpy(workBuffer, AddressString); - switch(AddressFamily) { case WS_AF_INET: { - struct in_addr inetaddr; + SOCKADDR_IN *addr4 = (SOCKADDR_IN *)lpAddress; /* If lpAddressLength is too small, tell caller the size we need */ if (*lpAddressLength < sizeof(SOCKADDR_IN)) @@ -8526,35 +8517,18 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString, *lpAddressLength = sizeof(SOCKADDR_IN); memset(lpAddress, 0, sizeof(SOCKADDR_IN)); - ((LPSOCKADDR_IN)lpAddress)->sin_family = WS_AF_INET; - - ptrPort = strchr(workBuffer, ':'); - if(ptrPort) + status = RtlIpv4StringToAddressExA(AddressString, FALSE, &addr4->sin_addr, &addr4->sin_port); + if (status != STATUS_SUCCESS) { - /* User may have entered an IPv6 and asked to parse as IPv4 */ - if(strchr(ptrPort + 1, ':')) - { - res = WSAEINVAL; - break; - } - ((LPSOCKADDR_IN)lpAddress)->sin_port = htons(atoi(ptrPort+1)); - *ptrPort = '\0'; - } - - if(inet_aton(workBuffer, &inetaddr) > 0) - { - ((LPSOCKADDR_IN)lpAddress)->sin_addr.WS_s_addr = inetaddr.s_addr; - res = 0; - } - else res = WSAEINVAL; - + break; + } + addr4->sin_family = WS_AF_INET; break; } case WS_AF_INET6: { - struct in6_addr inetaddr; - char *ptrAddr = workBuffer; + SOCKADDR_IN6 *addr6 = (SOCKADDR_IN6 *)lpAddress; /* If lpAddressLength is too small, tell caller the size we need */ if (*lpAddressLength < sizeof(SOCKADDR_IN6)) @@ -8563,42 +8537,16 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString, res = WSAEFAULT; break; } -#ifdef HAVE_INET_PTON *lpAddressLength = sizeof(SOCKADDR_IN6); memset(lpAddress, 0, sizeof(SOCKADDR_IN6)); - ((LPSOCKADDR_IN6)lpAddress)->sin6_family = WS_AF_INET6; - - /* Valid IPv6 addresses can also be surrounded by [ ], and in this case - * a port number may follow after like in [fd12:3456:7890::1]:12345 - * We need to cut the brackets and find the port if any. */ - - if(*workBuffer == '[') + status = RtlIpv6StringToAddressExA(AddressString, &addr6->sin6_addr, &addr6->sin6_scope_id, &addr6->sin6_port); + if (status != STATUS_SUCCESS) { - ptrPort = strchr(workBuffer, ']'); - if (!ptrPort) - { - SetLastError(WSAEINVAL); - return SOCKET_ERROR; - } - - if (ptrPort[1] == ':') - ((LPSOCKADDR_IN6)lpAddress)->sin6_port = htons(atoi(ptrPort + 2)); - - *ptrPort = '\0'; - ptrAddr = workBuffer + 1; - } - - if(inet_pton(AF_INET6, ptrAddr, &inetaddr) > 0) - { - memcpy(&((LPSOCKADDR_IN6)lpAddress)->sin6_addr, &inetaddr, - sizeof(struct in6_addr)); - res = 0; - } - else -#endif /* HAVE_INET_PTON */ res = WSAEINVAL; - + break; + } + addr6->sin6_family = WS_AF_INET6; break; } default: @@ -8607,8 +8555,6 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString, res = WSAEINVAL; } - HeapFree(GetProcessHeap(), 0, workBuffer); - if (!res) return 0; SetLastError(res); return SOCKET_ERROR; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index c6021f5ac31..9c996037ce3 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3429,6 +3429,8 @@ static void test_WSAStringToAddress(void) { "127.127.127.127:65535", 0x7f7f7f7f, 65535 }, { "255.255.255.255:65535", 0xffffffff, 65535 }, { "2001::1", 0xd1070000, 0, WSAEINVAL }, + { "1.2.3.", 0, 0, WSAEINVAL }, + { "", 0, 0, WSAEINVAL }, }; static struct { @@ -3445,6 +3447,10 @@ static void test_WSAStringToAddress(void) { "2001::1", { 0x120, 0, 0, 0, 0, 0, 0, 0x100 } }, { "::1]:65535", { 0, 0, 0, 0, 0, 0, 0, 0x100 }, 0, WSAEINVAL }, { "001::1", { 0x100, 0, 0, 0, 0, 0, 0, 0x100 } }, + { "::1:2:3:4:5:6:7", { 0, 0, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600 }, 0, WSAEINVAL }, /* Windows bug */ + { "1.2.3.4", { 0x201, 0x3, 0, 0, 0, 0, 0, 0 }, 0, WSAEINVAL }, + { "1:2:3:", { 0x100, 0x200, 0x300, 0, 0, 0, 0 }, 0, WSAEINVAL }, + { "", { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, WSAEINVAL }, }; WCHAR inputW[64]; @@ -3485,11 +3491,9 @@ static void test_WSAStringToAddress(void) ok( WSAGetLastError() == ipv4_tests[j].error, "WSAStringToAddress(%s) gave error %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), WSAGetLastError(), ipv4_tests[j].error ); -todo_wine_if(ipv4_tests[j].error) ok( sockaddr.sin_family == expected_family, "WSAStringToAddress(%s) gave family %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr.sin_family, expected_family ); -todo_wine_if(ipv4_tests[j].error) ok( sockaddr.sin_addr.s_addr == ipv4_tests[j].address, "WSAStringToAddress(%s) gave address %08x, expected %08x\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr.sin_addr.s_addr, ipv4_tests[j].address ); @@ -3526,11 +3530,9 @@ todo_wine_if(ipv4_tests[j].error) ok( WSAGetLastError() == ipv6_tests[j].error, "WSAStringToAddress(%s) gave error %d, expected %d\n", wine_dbgstr_a( ipv6_tests[j].input ), WSAGetLastError(), ipv6_tests[j].error ); -todo_wine_if(ipv6_tests[j].error) ok( sockaddr6.sin6_family == expected_family, "WSAStringToAddress(%s) gave family %d, expected %d\n", wine_dbgstr_a( ipv4_tests[j].input ), sockaddr6.sin6_family, expected_family ); -todo_wine_if(ipv6_tests[j].error) ok( memcmp(&sockaddr6.sin6_addr, ipv6_tests[j].address, sizeof(sockaddr6.sin6_addr)) == 0, "WSAStringToAddress(%s) gave address %x:%x:%x:%x:%x:%x:%x:%x, expected %x:%x:%x:%x:%x:%x:%x:%x\n", wine_dbgstr_a( ipv6_tests[j].input ),