From 727162317c02d673bdf11f3fbd10bf290e33b6b3 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Mon, 7 Jul 2025 22:59:09 +0300 Subject: [PATCH 1/9] [dotnet] Dispose socket object to find free tcp port --- .../src/webdriver/Internal/PortUtilities.cs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index ba80314622a5f..537624de95cd0 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -17,6 +17,7 @@ // under the License. // +using System; using System.Net; using System.Net.Sockets; @@ -33,23 +34,17 @@ public static class PortUtilities /// A random, free port to be listened on. public static int FindFreePort() { - // Locate a free port on the local machine by binding a socket to - // an IPEndPoint using IPAddress.Any and port 0. The socket will - // select a free port. - int listeningPort = 0; - Socket portSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + try { - IPEndPoint socketEndPoint = new IPEndPoint(IPAddress.Any, 0); - portSocket.Bind(socketEndPoint); - socketEndPoint = (IPEndPoint)portSocket.LocalEndPoint!; - listeningPort = socketEndPoint.Port; + socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + + return ((IPEndPoint)socket.LocalEndPoint!).Port; } - finally + catch (SocketException ex) { - portSocket.Close(); + throw new InvalidOperationException("Unable to find a free port.", ex); } - - return listeningPort; } } From 9788887e1459a4ab122425130c91ec603bb00ab7 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Mon, 7 Jul 2025 23:19:24 +0300 Subject: [PATCH 2/9] xml docs --- dotnet/src/webdriver/Internal/PortUtilities.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 537624de95cd0..dd9391dd4a0f2 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -32,6 +32,9 @@ public static class PortUtilities /// Finds a random, free port to be listened on. /// /// A random, free port to be listened on. + /// + /// Thrown when a free port cannot be found due to socket binding issues. + /// public static int FindFreePort() { using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); From d7ff72efce99ce48d3ef5b256688936ff5e2cb77 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 8 Jul 2025 22:52:35 +0300 Subject: [PATCH 3/9] Use TcpListener? --- dotnet/src/webdriver/Internal/PortUtilities.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index dd9391dd4a0f2..68911688d494a 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -37,17 +37,17 @@ public static class PortUtilities /// public static int FindFreePort() { - using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + var tcpListener = new TcpListener(IPAddress.IPv6Any, 0); try { - socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + tcpListener.Start(); - return ((IPEndPoint)socket.LocalEndPoint!).Port; + return ((IPEndPoint)tcpListener.LocalEndpoint).Port; } - catch (SocketException ex) + finally { - throw new InvalidOperationException("Unable to find a free port.", ex); + tcpListener.Stop(); } } } From 4b2490c7feb64fe793da11038b9e3d186720fd47 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 8 Jul 2025 23:20:24 +0300 Subject: [PATCH 4/9] Update PortUtilities.cs --- dotnet/src/webdriver/Internal/PortUtilities.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 68911688d494a..78dcdb1715d3a 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -32,13 +32,13 @@ public static class PortUtilities /// Finds a random, free port to be listened on. /// /// A random, free port to be listened on. - /// - /// Thrown when a free port cannot be found due to socket binding issues. - /// public static int FindFreePort() { var tcpListener = new TcpListener(IPAddress.IPv6Any, 0); + // Enable dual-mode to also work with IPv4 connections + tcpListener.Server.DualMode = true; + try { tcpListener.Start(); From c37403df7c871f90f24c0ccf89fbb2c770f218fc Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 8 Jul 2025 23:54:25 +0300 Subject: [PATCH 5/9] Fallback too ip4 --- .../src/webdriver/Internal/PortUtilities.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 78dcdb1715d3a..99aa6cc80deb0 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -17,7 +17,6 @@ // under the License. // -using System; using System.Net; using System.Net.Sockets; @@ -34,20 +33,23 @@ public static class PortUtilities /// A random, free port to be listened on. public static int FindFreePort() { - var tcpListener = new TcpListener(IPAddress.IPv6Any, 0); - - // Enable dual-mode to also work with IPv4 connections - tcpListener.Server.DualMode = true; - try { - tcpListener.Start(); - - return ((IPEndPoint)tcpListener.LocalEndpoint).Port; + var listener = new TcpListener(IPAddress.IPv6Any, 0); + listener.Server.DualMode = true; // Listen on both IPv4 and IPv6 + listener.Start(); + int port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + return port; } - finally + catch (SocketException) { - tcpListener.Stop(); + // If IPv6Any is not supported, fallback to IPv4 + var listener = new TcpListener(IPAddress.Any, 0); + listener.Start(); + int port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + return port; } } } From 264d1af990336469b3b6cc7936e785eed3d81062 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:11:06 +0300 Subject: [PATCH 6/9] Fine tuned and verified --- .../src/webdriver/Internal/PortUtilities.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 99aa6cc80deb0..3d33e3aef3cc9 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -33,23 +33,21 @@ public static class PortUtilities /// A random, free port to be listened on. public static int FindFreePort() { + // Locate a free port on the local machine by binding a socket to + // an IPEndPoint using IPAddress.Any and port 0. The socket will + // select a free port. try { - var listener = new TcpListener(IPAddress.IPv6Any, 0); - listener.Server.DualMode = true; // Listen on both IPv4 and IPv6 - listener.Start(); - int port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - return port; + using var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); + socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); + return (socket.LocalEndPoint as IPEndPoint)!.Port; } catch (SocketException) { - // If IPv6Any is not supported, fallback to IPv4 - var listener = new TcpListener(IPAddress.Any, 0); - listener.Start(); - int port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - return port; + // If IPv6 is not supported, fallback to IPv4 + using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + return (socket.LocalEndPoint as IPEndPoint)!.Port; } } } From 6e36192b3eb2530db1dc209ef3eea6c2d546e9b3 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:07:37 +0300 Subject: [PATCH 7/9] Use DualMode --- .../src/webdriver/Internal/PortUtilities.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 3d33e3aef3cc9..a739e5ccd32f6 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -33,21 +33,10 @@ public static class PortUtilities /// A random, free port to be listened on. public static int FindFreePort() { - // Locate a free port on the local machine by binding a socket to - // an IPEndPoint using IPAddress.Any and port 0. The socket will - // select a free port. - try - { - using var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); - socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); - return (socket.LocalEndPoint as IPEndPoint)!.Port; - } - catch (SocketException) - { - // If IPv6 is not supported, fallback to IPv4 - using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); - return (socket.LocalEndPoint as IPEndPoint)!.Port; - } + 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; + } } From d0f43535a921727f09bd30a3fe476758522e443d Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 11 Jul 2025 20:16:01 +0300 Subject: [PATCH 8/9] Return back Any instead of Loopback casue I don't know usage of it Just to not break --- dotnet/src/webdriver/Internal/PortUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index a739e5ccd32f6..4b8025a7857a7 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -35,7 +35,7 @@ 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)); + socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0)); return (socket.LocalEndPoint as IPEndPoint)!.Port; } From edceb47a8a9f9d5a4d37797b0ccf71a23c33a9e0 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 11 Jul 2025 21:12:00 +0300 Subject: [PATCH 9/9] Return back loopback cause we don't own this port --- dotnet/src/webdriver/Internal/PortUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/webdriver/Internal/PortUtilities.cs b/dotnet/src/webdriver/Internal/PortUtilities.cs index 4b8025a7857a7..a739e5ccd32f6 100644 --- a/dotnet/src/webdriver/Internal/PortUtilities.cs +++ b/dotnet/src/webdriver/Internal/PortUtilities.cs @@ -35,7 +35,7 @@ public static int FindFreePort() { using var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); socket.DualMode = true; - socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0)); + socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0)); return (socket.LocalEndPoint as IPEndPoint)!.Port; }