diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index fd2a67c8c9e..0df8c0aa45f 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -967,27 +967,30 @@ sub get_new_node $found = 0 if ($node->port == $port); } - # Check to see if anything else is listening on this TCP port. Accept - # only ports available for all possible listen_addresses values, so - # the caller can harness this port for the widest range of purposes. - # This is *necessary* on Windows, and seems like a good idea on Unixen - # as well, even though we don't ask the postmaster to open a TCP port - # on Unix. + # Check to see if anything else is listening on this TCP port. This + # is *necessary* on $use_tcp (Windows) configurations. Seek a port + # available for all possible listen_addresses values, for own_host + # nodes and so the caller can harness this port for the widest range + # of purposes. The 0.0.0.0 test achieves that for post-2006 Cygwin, + # which automatically sets SO_EXCLUSIVEADDRUSE. The same holds for + # MSYS (a Cygwin fork). Testing 0.0.0.0 is insufficient for Windows + # native Perl (https://stackoverflow.com/a/14388707), so we also test + # individual addresses. + # + # This seems like a good idea on Unixen as well, even though we don't + # ask the postmaster to open a TCP port on Unix. On Non-Linux, + # non-Windows kernels, binding to 127.0.0.1/24 addresses other than + # 127.0.0.1 fails with EADDRNOTAVAIL. + # + # XXX A port available now may become unavailable by the time we start + # the postmaster. if ($found == 1) { - my $iaddr = inet_aton('0.0.0.0'); - my $paddr = sockaddr_in($port, $iaddr); - my $proto = getprotobyname("tcp"); - - socket(SOCK, PF_INET, SOCK_STREAM, $proto) - or die "socket failed: $!"; - - # As in postmaster, don't use SO_REUSEADDR on Windows - setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) - unless $TestLib::windows_os; - (bind(SOCK, $paddr) && listen(SOCK, SOMAXCONN)) - or $found = 0; - close(SOCK); + foreach my $addr (qw(127.0.0.1 0.0.0.0), + $use_tcp ? qw(127.0.0.2 127.0.0.3) : ()) + { + can_bind($addr, $port) or $found = 0; + } } } @@ -999,8 +1002,6 @@ sub get_new_node { if ($use_tcp) { - # This assumes $use_tcp platforms treat every address in - # 127.0.0.1/24, not just 127.0.0.1, as a usable loopback. $last_host_assigned++; $last_host_assigned > 254 and BAIL_OUT("too many own_host nodes"); $host = '127.0.0.' . $last_host_assigned; @@ -1024,6 +1025,25 @@ sub get_new_node return $node; } +# Internal routine to check whether a host:port is available to bind +sub can_bind +{ + my ($host, $port) = @_; + my $iaddr = inet_aton($host); + my $paddr = sockaddr_in($port, $iaddr); + my $proto = getprotobyname("tcp"); + + socket(SOCK, PF_INET, SOCK_STREAM, $proto) + or die "socket failed: $!"; + + # As in postmaster, don't use SO_REUSEADDR on Windows + setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) + unless $TestLib::windows_os; + my $ret = bind(SOCK, $paddr) && listen(SOCK, SOMAXCONN); + close(SOCK); + return $ret; +} + # Automatically shut down any still-running nodes when the test script exits. # Note that this just stops the postmasters (in the same order the nodes were # created in). Temporary PGDATA directories are deleted, in an unspecified