use more reliable checks in wait_for_vnc_port
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Tue, 27 Jun 2017 09:12:04 +0000 (11:12 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Tue, 27 Jun 2017 09:22:55 +0000 (11:22 +0200)
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@proxmox.com>
src/PVE/Tools.pm

index da7da5d..f9ca118 100644 (file)
@@ -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);
     }