Choose ports for test servers less likely to result in conflicts
authorAndrew Dunstan <andrew@dunslane.net>
Mon, 8 Jul 2024 15:18:06 +0000 (11:18 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Mon, 8 Jul 2024 15:40:58 +0000 (11:40 -0400)
If we choose ports in the range typically used for ephemeral ports there
is a danger of encountering a port conflict due to a race condition
between the time we choose the port in a range below that typically used
to allocate ephemeral ports, but higher than the range typically used by
well known services.

Author: Jelte Fenema-Nio, with some editing by me.

Discussion: https://postgr.es/m/d6ee8761-39d1-0033-1afb-d5a57ee056f2@gmail.com

Backpatch to all live branches (12 and up)

src/test/perl/PostgresNode.pm

index 87bfa67eff8efdbdeb809aef9d4b04ab4a0eebe3..a246c73f04ea4248cb0cad95d1a65feb635a11c0 100644 (file)
@@ -116,6 +116,14 @@ our ($use_tcp, $test_localhost, $test_pghost, $last_host_assigned,
 # list of file reservations made by get_free_port
 my @port_reservation_files;
 
+# We want to choose a server port above the range that servers typically use
+# on Unix systems and below the range those systems typically use for ephemeral
+# client ports.
+# That way we minimize the risk of getting a port collision. These two values
+# are chosen to reflect that. We will always choose a port in this range.
+my $port_lower_bound = 10200;
+my $port_upper_bound = 32767;
+
 INIT
 {
 
@@ -129,7 +137,8 @@ INIT
    $ENV{PGDATABASE}    = 'postgres';
 
    # Tracking of last port value assigned to accelerate free port lookup.
-   $last_port_assigned = int(rand() * 16384) + 49152;
+   my $num_ports = $port_upper_bound - $port_lower_bound;
+   $last_port_assigned = int(rand() * $num_ports) + $port_lower_bound;
 
    # Set the port lock directory
 
@@ -1214,7 +1223,7 @@ sub get_free_port
    {
 
        # advance $port, wrapping correctly around range end
-       $port = 49152 if ++$port >= 65536;
+       $port = $port_lower_bound if ++$port > $port_upper_bound;
        print "# Checking port $port\n";
 
        # Check first that candidate port number is not included in