Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com --- dlls/iphlpapi/tests/iphlpapi.c | 225 +++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+)
diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index be50cc0b476..09049b2af0f 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -2391,6 +2391,230 @@ static void test_GetUnicastIpAddressTable(void) FreeMibTable( table ); }
+static void set_sockaddr_ipv4( SOCKADDR_INET *sockaddr, ULONG in_addr ) +{ + memset( sockaddr, 0, sizeof(*sockaddr) ); + sockaddr->Ipv4.sin_family = AF_INET; + sockaddr->Ipv4.sin_addr.S_un.S_addr = in_addr; +} + +static void test_GetBestRoute2(void) +{ + DWORD apiReturn; + SOCKADDR_INET source, destination, bestaddress, bestaddress_memory; + MIB_IPFORWARD_ROW2 bestroute, bestroute_memory; + int validmemflags = 0; + static const MIB_IPFORWARD_ROW2 route_zero; + static const NET_LUID zero_luid, ones_luid = { -1 }; + static const SOCKADDR_INET unspecaddr; + static const SOCKADDR invalidaddr = { -1 }; + static const SOCKADDR_IN in4any = { AF_INET }; + static const SOCKADDR_IN in4loopback = { AF_INET, 0, {{{ 127, 0, 0, 1 }}} }; + static const SOCKADDR_IN in4broadcast = { AF_INET, 0, {{{ 255, 255, 255, 255 }}} }; + static const SOCKADDR_IN6 in6any = { AF_INET6 }; + static const SOCKADDR_IN6 in6loopback = { AF_INET6, 0, 0, {{{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }}} }; + static const SOCKADDR_IN6 in6broadcast = { AF_INET6, 0, 0, {{{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }}} }; + struct sockaddr_ptrlen + { + const struct sockaddr *ptr; + size_t len; + }; + static const struct getbestroute_test + { + int line; + const NET_LUID *luid; + NET_IFINDEX ifindex; + struct sockaddr_ptrlen source; + struct sockaddr_ptrlen destination; + ULONG options; + DWORD result; + BOOL todo; + int memload; + int memstore; + } getbestroute_tests[] = { +#define SA_PL(x) { ((struct sockaddr *)&(x)), sizeof(x) } + { __LINE__, &zero_luid, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, &zero_luid, -1, { NULL }, SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, &ones_luid, 0, { NULL }, SA_PL(in4loopback), 0, ERROR_NOT_FOUND }, + { __LINE__, NULL, -1, { NULL }, SA_PL(in4loopback), 0, ERROR_FILE_NOT_FOUND }, + { __LINE__, &zero_luid, 0, SA_PL(unspecaddr), SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, &ones_luid, 0, SA_PL(unspecaddr), SA_PL(in4loopback), 0, ERROR_NOT_FOUND }, + { __LINE__, NULL, 0, SA_PL(unspecaddr), SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, NULL, 0, SA_PL(in4any), SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, NULL, 0, SA_PL(in4loopback), SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, NULL, 0, SA_PL(in4broadcast),SA_PL(in4loopback), 0, ERROR_INVALID_PARAMETER, TRUE }, + { __LINE__, NULL, 0, SA_PL(in6any), SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, NULL, 0, SA_PL(in6loopback), SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, NULL, 0, SA_PL(in6broadcast),SA_PL(in4loopback), 0, NO_ERROR }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0, 0xc7 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc0 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc2 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc4 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc6 }, +#if 0 /* not reliable (fails spuriously) on Wine */ + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc1 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc3 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc5 }, + { __LINE__, NULL, 0, { NULL }, SA_PL(in4loopback), 0, NO_ERROR, FALSE, 0xc7 }, +#endif +#undef SA_PL + }; + UINT i; + + set_sockaddr_ipv4( &destination, INADDR_ANY ); + apiReturn = GetBestRoute2( NULL, 0, NULL, &destination, 0, &bestroute, &bestaddress ); + trace( "GetBestRoute2(NULL, 0, NULL, [...], 0, [...], [...]) = %d\n", apiReturn ); + if (apiReturn == ERROR_NOT_SUPPORTED) + { + skip("GetBestRoute2 not supported\n"); + return; + } + + apiReturn = GetBestRoute2( NULL, 0, NULL, NULL, 0, NULL, NULL ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, NULL, 0, NULL, NULL) returned %u, expected %u\n", + apiReturn, ERROR_INVALID_PARAMETER ); + + apiReturn = GetBestRoute2( NULL, 0, NULL, NULL, 0, &bestroute, NULL ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, NULL, 0, %p, NULL) returned %u, expected %u\n", + &bestroute, apiReturn, ERROR_INVALID_PARAMETER ); + + apiReturn = GetBestRoute2( NULL, 0, NULL, NULL, 0, NULL, &bestaddress ); + memcpy( &bestaddress, &invalidaddr, sizeof(invalidaddr) ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, NULL, 0, NULL, %p) returned %u, expected %u\n", + &bestaddress, apiReturn, ERROR_INVALID_PARAMETER ); + ok( memcmp(&bestaddress, &invalidaddr, sizeof(invalidaddr)) == 0, "bestaddress(.si_family = %u) has changed\n", bestaddress.si_family ); + + apiReturn = GetBestRoute2( NULL, 0, NULL, NULL, 0, &bestroute, &bestaddress ); + memcpy( &bestaddress, &invalidaddr, sizeof(invalidaddr) ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, NULL, 0, %p, %p) returned %u, expected %u\n", + &bestroute, &bestaddress, apiReturn, ERROR_INVALID_PARAMETER ); + ok( memcmp(&bestaddress, &invalidaddr, sizeof(invalidaddr)) == 0, "bestaddress(.si_family = %u) has changed\n", bestaddress.si_family ); + + set_sockaddr_ipv4( &destination, INADDR_LOOPBACK ); + memcpy( &bestaddress, &invalidaddr, sizeof(invalidaddr) ); + apiReturn = GetBestRoute2( NULL, 0, NULL, &destination, 0, &bestroute, NULL ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, [127.0.0.1], 0, %p, NULL) returned %u, expected %u\n", + &bestroute, apiReturn, ERROR_INVALID_PARAMETER ); + ok( memcmp(&bestaddress, &invalidaddr, sizeof(invalidaddr)) == 0, "bestaddress(.si_family = %u) has changed\n", bestaddress.si_family ); + + set_sockaddr_ipv4( &destination, INADDR_LOOPBACK ); + memcpy( &bestaddress, &invalidaddr, sizeof(invalidaddr) ); + apiReturn = GetBestRoute2( NULL, 0, NULL, &destination, 0, NULL, &bestaddress ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, [127.0.0.1], 0, NULL, %p) returned %u, expected %u\n", + &bestaddress, apiReturn, ERROR_INVALID_PARAMETER ); + ok( memcmp(&bestaddress, &invalidaddr, sizeof(invalidaddr)) == 0, "bestaddress(.si_family = %u) has changed\n", bestaddress.si_family ); + + memset( &destination, 0, sizeof(destination) ); + memcpy( &bestaddress, &invalidaddr, sizeof(invalidaddr) ); + apiReturn = GetBestRoute2( NULL, 0, NULL, &destination, 0, NULL, &bestaddress ); + ok( apiReturn == ERROR_INVALID_PARAMETER, + "GetBestRoute2(NULL, 0, NULL, <AF_UNSPEC>, 0, NULL, %p) returned %u, expected %u\n", + &bestaddress, apiReturn, ERROR_INVALID_PARAMETER ); + ok( memcmp(&bestaddress, &invalidaddr, sizeof(invalidaddr)) == 0, "bestaddress(.si_family = %u) has changed\n", bestaddress.si_family ); + + for (i = 0; i < ARRAY_SIZE(getbestroute_tests); i++) + { + const struct getbestroute_test *item = &getbestroute_tests[i]; + int validflags = item->memload & validmemflags; + NET_LUID luid; + NET_IFINDEX ifindex = 0; + + winetest_push_context("Subtest #%u (decl at line %d)", i, item->line); + + ok( (item->memload & ~validmemflags) == 0, + "current subtest may be incomplete due to previous test failure (memload = %d, validmemflags = %d)\n", + item->memload, validmemflags ); + + if (item->luid) + { + memcpy(&luid, item->luid, sizeof(luid)); + validflags |= 1; + } + else if (validflags & 1) + { + memcpy(&luid, &bestroute_memory.InterfaceLuid, sizeof(luid)); + } + + if (item->ifindex) + { + ifindex = item->ifindex; + validflags |= 2; + } + else if (validflags & 2) + { + ifindex = bestroute_memory.InterfaceIndex; + } + + if (item->source.len > sizeof(source)) abort(); /* prevent memory corruption */ + if (item->source.ptr) + { + memset( &source, 0, sizeof(source) ); + memcpy( &source, item->source.ptr, item->source.len ); + validflags |= 4; + } + else if (validflags & 4) + { + memcpy( &source, &bestaddress_memory, sizeof(source) ); + } + + if (item->destination.len > sizeof(destination)) abort(); /* prevent memory corruption */ + memset( &destination, 0, sizeof(destination) ); + memcpy( &destination, item->destination.ptr, item->destination.len ); + + apiReturn = GetBestRoute2( (validflags & 1) ? &luid : NULL, + (validflags & 2) ? ifindex : 0, + (validflags & 4) ? &source : NULL, + &destination, + item->options, + &bestroute, &bestaddress ); + todo_wine_if( item->todo ) + ok( apiReturn == item->result, + "GetBestRoute2 returned %u, expected %u\n", apiReturn, item->result ); + if (apiReturn == NO_ERROR) + { + ok( bestaddress.si_family == destination.si_family, + "bestaddress.si_family (%u) shall equal destination.si_family (%u)\n", + bestaddress.si_family, destination.si_family ); + + if (validflags & 0x40) + { + ok( memcmp( &bestroute_memory, &bestroute, sizeof(bestroute) ) == 0, + "returned bestroute does not match last cached value\n" ); + } + + if (validflags & 0x80) + { + ok( memcmp( &bestaddress_memory, &bestaddress, sizeof(bestaddress) ) == 0, + "returned bestaddress does not match last cached value\n" ); + } + + if (item->memstore) + { + memcpy( &bestroute_memory, &bestroute, sizeof(bestroute_memory) ); + memcpy( &bestaddress_memory, &bestaddress, sizeof(bestaddress_memory) ); + validmemflags = item->memstore; + } + } + else + { + ok( memcmp( &bestaddress, &unspecaddr, sizeof(bestaddress) ) == 0, "bestaddress shall be zeroed by GetBestRoute2\n" ); + ok( memcmp( &bestroute, &route_zero, sizeof(bestroute) ) == 0, "bestroute shall be zeroed by GetBestRoute2\n" ); + } + + winetest_pop_context(); + } +} + static void test_ConvertLengthToIpv4Mask(void) { DWORD ret; @@ -2703,6 +2927,7 @@ START_TEST(iphlpapi) test_GetIfTable2Ex(); test_GetUnicastIpAddressEntry(); test_GetUnicastIpAddressTable(); + test_GetBestRoute2(); test_ConvertLengthToIpv4Mask(); test_GetTcp6Table(); test_GetUdp6Table();