]> granicus.if.org Git - postgresql/commitdiff
Test both 0.0.0.0 and 127.0.0.x addresses to find a usable port.
authorNoah Misch <noah@leadboat.com>
Mon, 15 Apr 2019 03:02:19 +0000 (20:02 -0700)
committerNoah Misch <noah@leadboat.com>
Mon, 15 Apr 2019 03:03:48 +0000 (20:03 -0700)
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

src/test/perl/PostgresNode.pm

index 52708205850b15f3578033949e1a8fa1bcd382da..471e0ad6ce55b15551db9c929c2ff22fa8d2fd22 100644 (file)
@@ -977,27 +977,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;
+                       }
                }
        }
 
@@ -1009,8 +1012,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;
@@ -1034,6 +1035,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