From fa8f9e785a74f1aea8baa897a573adab7d1503c3 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:14:46 +0300 Subject: [PATCH 1/4] [dotnet] Fix find port for IPv4 only environments --- .../src/webdriver/Internal/PortUtilities.cs | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index a739e5ccd32f6..8ab2ebe45ba2d 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -33,10 +33,30 @@ public static class PortUtilities /// A random, free port to be listened on. public static int FindFreePort() { - using var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); - socket.DualMode = true; - socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); - return (socket.LocalEndPoint as IPEndPoint)!.Port; + // Prefer IPv6 dual-mode when available, but fall back robustly to IPv4 + try + { + using var ipV6socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); + // Some platforms may not support DualMode or IPv6 at all; ignore failures and let bind decide + try + { + ipV6socket.DualMode = true; + } + catch + { + // Ignored; we'll still attempt to bind to IPv6 loopback + } + + ipV6socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); + return ((IPEndPoint)ipV6socket.LocalEndPoint!).Port; + } + catch(SocketException) + { + // If creating/binding the IPv6 socket fails for any reason, fall back to IPv4 + using var ipV4socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + ipV4socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + return ((IPEndPoint)ipV4socket.LocalEndPoint!).Port; + } } } From 80190d829ac3a800ce5908df407d7e97c08ae7be Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:26:23 +0300 Subject: [PATCH 2/4] Try ipv4 and fallback to ipv6 --- .../src/webdriver/Internal/PortUtilities.cs | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 8ab2ebe45ba2d..d7c1a3553fca3 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -33,30 +33,19 @@ public static class PortUtilities /// A random, free port to be listened on. public static int FindFreePort() { - // Prefer IPv6 dual-mode when available, but fall back robustly to IPv4 + // Prefer IPv4, but fall back robustly to IPv6 try { - using var ipV6socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); - - // Some platforms may not support DualMode or IPv6 at all; ignore failures and let bind decide - try - { - ipV6socket.DualMode = true; - } - catch - { - // Ignored; we'll still attempt to bind to IPv6 loopback - } - - ipV6socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); - return ((IPEndPoint)ipV6socket.LocalEndPoint!).Port; - } - catch(SocketException) - { - // If creating/binding the IPv6 socket fails for any reason, fall back to IPv4 using var ipV4socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ipV4socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); return ((IPEndPoint)ipV4socket.LocalEndPoint!).Port; } + catch (SocketException) + { + // If creating/binding the IPv4 socket fails for any reason, fall back to IPv6 + using var ipV6socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); + ipV6socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); + return ((IPEndPoint)ipV6socket.LocalEndPoint!).Port; + } } } From b6f22ffae6e68c41c3769d60ab6ffdcf03e34ed8 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:28:04 +0300 Subject: [PATCH 3/4] Update PortUtilities.cs --- dotnet/src/webdriver/Internal/PortUtilities.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index d7c1a3553fca3..e07c18750a328 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -28,12 +28,11 @@ namespace OpenQA.Selenium.Internal; public static class PortUtilities { /// - /// Finds a random, free port to be listened on. + /// Finds a random, free port to be listened on. Prefers IPv4, but falls back to IPv6 if necessary. /// /// A random, free port to be listened on. public static int FindFreePort() { - // Prefer IPv4, but fall back robustly to IPv6 try { using var ipV4socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -42,7 +41,6 @@ public static int FindFreePort() } catch (SocketException) { - // If creating/binding the IPv4 socket fails for any reason, fall back to IPv6 using var ipV6socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); ipV6socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); return ((IPEndPoint)ipV6socket.LocalEndPoint!).Port; From 2114addd6a5165828d2fac3cf2f518db95a3f1d5 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:45:45 +0300 Subject: [PATCH 4/4] Move tech desription to remarks --- dotnet/src/webdriver/Internal/PortUtilities.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index e07c18750a328..6f67d5abbd4b6 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -28,8 +28,11 @@ namespace OpenQA.Selenium.Internal; public static class PortUtilities { /// - /// Finds a random, free port to be listened on. Prefers IPv4, but falls back to IPv6 if necessary. + /// Finds a random, free port to be listened on. /// + /// + /// Prefers IPv4, but falls back to IPv6 if necessary. + /// /// A random, free port to be listened on. public static int FindFreePort() {