1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-12 16:21:30 +03:00

Test both 0.0.0.0 and 127.0.0.x addresses to find a usable port.

Commit c098509927f9a49ebceb301a2cb6a477ecd4ac3c changed
PostgresNode::get_new_node() to probe 0.0.0.0 instead of 127.0.0.1, but
the new test was less effective for Windows native Perl.  This increased
the failure rate of buildfarm members bowerbird and jacana.  Instead,
test 0.0.0.0 and concrete addresses.  This restores the old level of
defense, but the algorithm is still subject to its longstanding time of
check to time of use race condition.  Back-patch to 9.6, like the
previous change.

Discussion: https://postgr.es/m/GrdLgAdUK9FdyZg8VIcTDKVOkys122ZINEb3CjjoySfGj2KyPiMKTh1zqtRp0TAD7FJ27G-OBB3eplxIB5GhcQH5o8zzGZfp0MuJaXJxVxk=@yesql.se
This commit is contained in:
Noah Misch 2019-04-14 20:02:19 -07:00
parent 6b7906e1d9
commit 9f65081cf7

View File

@ -967,27 +967,30 @@ sub get_new_node
$found = 0 if ($node->port == $port); $found = 0 if ($node->port == $port);
} }
# Check to see if anything else is listening on this TCP port. Accept # Check to see if anything else is listening on this TCP port. This
# only ports available for all possible listen_addresses values, so # is *necessary* on $use_tcp (Windows) configurations. Seek a port
# the caller can harness this port for the widest range of purposes. # available for all possible listen_addresses values, for own_host
# This is *necessary* on Windows, and seems like a good idea on Unixen # nodes and so the caller can harness this port for the widest range
# as well, even though we don't ask the postmaster to open a TCP port # of purposes. The 0.0.0.0 test achieves that for post-2006 Cygwin,
# on Unix. # 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) if ($found == 1)
{ {
my $iaddr = inet_aton('0.0.0.0'); foreach my $addr (qw(127.0.0.1 0.0.0.0),
my $paddr = sockaddr_in($port, $iaddr); $use_tcp ? qw(127.0.0.2 127.0.0.3) : ())
my $proto = getprotobyname("tcp"); {
can_bind($addr, $port) or $found = 0;
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);
} }
} }
@ -999,8 +1002,6 @@ sub get_new_node
{ {
if ($use_tcp) 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++;
$last_host_assigned > 254 and BAIL_OUT("too many own_host nodes"); $last_host_assigned > 254 and BAIL_OUT("too many own_host nodes");
$host = '127.0.0.' . $last_host_assigned; $host = '127.0.0.' . $last_host_assigned;
@ -1024,6 +1025,25 @@ sub get_new_node
return $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. # 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 # Note that this just stops the postmasters (in the same order the nodes were
# created in). Temporary PGDATA directories are deleted, in an unspecified # created in). Temporary PGDATA directories are deleted, in an unspecified