From 44497367f88096a9f91439682b3c0460bf905eb0 Mon Sep 17 00:00:00 2001
From: Andrew Ruthven <andrew@etc.gen.nz>
Date: Thu, 26 Sep 2024 16:19:18 +1200
Subject: Change free port detection to how PSGI binds to a port

The previous method using socket/connect would allow us to bind to a
port that PSGI then couldn't bind to. If a port is connected on
a specific IP, then using connect with 0.0.0.0 would still connect
okay.

Using IO::Socket::INET this will fail, which is reasonable for 0.0.0.0,
and then PSGI wouldn't be able to start and the test would fail.

This may resolve the intermittant test failures.

Patch-Name: use-io-socket-inet-in-tests.diff
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1074781
Bug: https://rt.bestpractical.com/Ticket/Display.html?id=37886
Forwarded: https://github.com/bestpractical/rt/pull/392
---
 lib/RT/Test.pm | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/RT/Test.pm b/lib/RT/Test.pm
index 3954dd54..ebc010ce 100644
--- a/lib/RT/Test.pm
+++ b/lib/RT/Test.pm
@@ -69,6 +69,7 @@ my $Test_NoWarnings_Catcher = $SIG{__WARN__};
 my $check_warnings_in_end   = 1;
 
 use Socket;
+use IO::Socket::INET;
 use File::Temp qw(tempfile);
 use File::Path qw(mkpath);
 use File::Spec;
@@ -257,14 +258,17 @@ sub find_idle_port {
         # server binds.  However, since we mostly care about race
         # conditions with ourselves under high concurrency, this is
         # generally good enough.
-        my $paddr = sockaddr_in( $port, inet_aton('localhost') );
-        socket( SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp') )
-            or die "socket: $!";
-        if ( connect( SOCK, $paddr ) ) {
-            close(SOCK);
+
+        if (! IO::Socket::INET->new(
+            Listen    => SOMAXCONN,
+            LocalPort => $port,
+            LocalAddr => '0.0.0.0',
+            Proto     => 'tcp',
+            ReuseAddr => 1,
+        )) {
+            # Port is probably busy.
             redo;
         }
-        close(SOCK);
     }
 
     $ports{$port}++;
