diff --git a/ares__sortaddrinfo.c b/ares__sortaddrinfo.c index c0e2ea152..58f8a0780 100644 --- a/ares__sortaddrinfo.c +++ b/ares__sortaddrinfo.c @@ -427,7 +427,7 @@ static int find_src_addr(ares_channel channel, return 0; } - if (getsockname(sock, src_addr, &len) == -1) + if (getsockname(sock, src_addr, &len) != 0) { ares__close_socket(channel, sock); return -1; diff --git a/test/ares-test.cc b/test/ares-test.cc index ec4b46054..9cfb64b33 100644 --- a/test/ares-test.cc +++ b/test/ares-test.cc @@ -30,7 +30,8 @@ namespace ares { namespace test { bool verbose = false; -int mock_port = 5300; +static constexpr int dynamic_port = 0; +int mock_port = dynamic_port; const std::vector both_families = {AF_INET, AF_INET6}; const std::vector ipv4_family = {AF_INET}; @@ -169,8 +170,8 @@ void DefaultChannelModeTest::Process() { ProcessWork(channel_, NoExtraFDs, nullptr); } -MockServer::MockServer(int family, int port, int tcpport) - : udpport_(port), tcpport_(tcpport ? tcpport : udpport_), qid_(-1) { +MockServer::MockServer(int family, int port) + : udpport_(port), tcpport_(port), qid_(-1) { // Create a TCP socket to receive data on. tcpfd_ = socket(family, SOCK_STREAM, 0); EXPECT_NE(-1, tcpfd_); @@ -197,6 +198,21 @@ MockServer::MockServer(int family, int port, int tcpport) addr.sin_port = htons(udpport_); int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr)); EXPECT_EQ(0, udprc) << "Failed to bind AF_INET to UDP port " << udpport_; + // retrieve system-assigned port + if (udpport_ == dynamic_port) { + ares_socklen_t len = sizeof(addr); + auto result = getsockname(udpfd_, (struct sockaddr*)&addr, &len); + EXPECT_EQ(0, result); + udpport_ = ntohs(addr.sin_port); + EXPECT_NE(dynamic_port, udpport_); + } + if (tcpport_ == dynamic_port) { + ares_socklen_t len = sizeof(addr); + auto result = getsockname(tcpfd_, (struct sockaddr*)&addr, &len); + EXPECT_EQ(0, result); + tcpport_ = ntohs(addr.sin_port); + EXPECT_NE(dynamic_port, tcpport_); + } } else { EXPECT_EQ(AF_INET6, family); struct sockaddr_in6 addr; @@ -209,6 +225,21 @@ MockServer::MockServer(int family, int port, int tcpport) addr.sin6_port = htons(udpport_); int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr)); EXPECT_EQ(0, udprc) << "Failed to bind AF_INET6 to UDP port " << udpport_; + // retrieve system-assigned port + if (udpport_ == dynamic_port) { + ares_socklen_t len = sizeof(addr); + auto result = getsockname(udpfd_, (struct sockaddr*)&addr, &len); + EXPECT_EQ(0, result); + udpport_ = ntohs(addr.sin6_port); + EXPECT_NE(dynamic_port, udpport_); + } + if (tcpport_ == dynamic_port) { + ares_socklen_t len = sizeof(addr); + auto result = getsockname(tcpfd_, (struct sockaddr*)&addr, &len); + EXPECT_EQ(0, result); + tcpport_ = ntohs(addr.sin6_port); + EXPECT_NE(dynamic_port, tcpport_); + } } if (verbose) std::cerr << "Configured " << (family == AF_INET ? "IPv4" : "IPv6") @@ -381,7 +412,8 @@ MockChannelOptsTest::NiceMockServers MockChannelOptsTest::BuildServers(int count NiceMockServers servers; assert(count > 0); for (int ii = 0; ii < count; ii++) { - std::unique_ptr server(new NiceMockServer(family, base_port + ii)); + int port = base_port == dynamic_port ? dynamic_port : base_port + ii; + std::unique_ptr server(new NiceMockServer(family, port)); servers.push_back(std::move(server)); } return servers; @@ -403,9 +435,9 @@ MockChannelOptsTest::MockChannelOptsTest(int count, } // Point the library at the first mock server by default (overridden below). - opts.udp_port = mock_port; + opts.udp_port = server_.udpport(); optmask |= ARES_OPT_UDP_PORT; - opts.tcp_port = mock_port; + opts.tcp_port = server_.tcpport(); optmask |= ARES_OPT_TCP_PORT; // If not already overridden, set short-ish timeouts. diff --git a/test/ares-test.h b/test/ares-test.h index a3d1d37c1..e92bf3b05 100644 --- a/test/ares-test.h +++ b/test/ares-test.h @@ -136,7 +136,7 @@ class DefaultChannelModeTest // Mock DNS server to allow responses to be scripted by tests. class MockServer { public: - MockServer(int family, int port, int tcpport = 0); + MockServer(int family, int port); ~MockServer(); // Mock method indicating the processing of a particular