[pve-devel] [RFC common] use more reliable checks in wait_for_vnc_port

Thomas Lamprecht t.lamprecht at proxmox.com
Tue Jun 27 11:12:04 CEST 2017


We run into problems where this method returned to early, even if the
port wasn't actually ready yet. The reason for this is that we
checked /proc/net/tcp which does not guarantees and always up to date
state of only those ports which are actuall available, i.e. a port
could linger around (time-wait state) or appear even if it wasn't
accepting connections yet (as stated in the kernel docs:
/proc/net/tcp is seen as obsolete by the kernel devs).

Use the `ss` tool from the iproute2 package, it uses netlink to get
the current state and has switches where we can direct it to really
only get the state of those sockets which interest us currently.
I.e., we tell it to get only listening TCP sockets from the requested
port.

The only drawback is that we loop on a run_command, which is slower
than just reading a file. A single loop needs about 1ms here vs the
60µs on the /proc/net/tcp read. But this isn't a api call which is
used highly frequently but rather once per noVNC console open.

Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---

The best alternative would be using a netlink socket directly here,
but as we have no netlink module with common helpers/abstraction yet
and time is rather short for adding it or a specialised version of
this for 5.0 now, imo.

 src/PVE/Tools.pm | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm
index da7da5d..f9ca118 100644
--- a/src/PVE/Tools.pm
+++ b/src/PVE/Tools.pm
@@ -739,18 +739,16 @@ sub wait_for_vnc_port {
     my $starttime = [gettimeofday];
     my $elapsed;
 
+    my $found;
     while (($elapsed = tv_interval($starttime)) < $timeout) {
-	if (my $fh = IO::File->new ("/proc/net/tcp", "r")) {
-	    while (defined (my $line = <$fh>)) {
-		if ($line =~ m/^\s*\d+:\s+([0-9A-Fa-f]{8}):([0-9A-Fa-f]{4})\s/) {
-		    if ($port == hex($2)) {
-			close($fh);
-			return 1;
-		    }
-		}
+	# -Htln = don't print header, tcp, listening sockets only, numeric ports
+	run_command(['/bin/ss', '-Htln', "sport = :$port"], outfunc => sub {
+	    my $line = shift;
+	    if ($line =~ m/^LISTEN\s+\d+\s+\d+\s+\S+:(\d+)\s/) {
+		$found = 1 if ($port == $1);
 	    }
-	    close($fh);
-	}
+	});
+	return 1 if $found;
 	$sleeptime += 100000 if  $sleeptime < 1000000;
 	usleep($sleeptime);
     }
-- 
2.11.0





More information about the pve-devel mailing list