[pve-devel] applied: [PATCH pve-client 2/2] lxc enter: simplify code and cleanups

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Jun 6 15:25:14 CEST 2018


applied, but two comments inline...

On Wed, Jun 06, 2018 at 11:30:13AM +0200, Dietmar Maurer wrote:
> - print error messages after reseting the terminal
> - catch signals
> 
> Signed-off-by: Dietmar Maurer <dietmar at proxmox.com>
> ---
>  PVE/APIClient/Commands/lxc.pm | 152 +++++++++++++++++-------------------------
>  1 file changed, 63 insertions(+), 89 deletions(-)
> 
> diff --git a/PVE/APIClient/Commands/lxc.pm b/PVE/APIClient/Commands/lxc.pm
> index df72625..81dfd3f 100644
> --- a/PVE/APIClient/Commands/lxc.pm
> +++ b/PVE/APIClient/Commands/lxc.pm
> @@ -128,35 +128,6 @@ my $parse_web_socket_frame = sub  {
>      return ($payload, $req_close);
>  };
>  
> -my $client_exit = sub {
> -    my ($select, $web_socket, $old_termios) = @_;
> -
> -    foreach my $fh ($select->handles) {
> -	$select->remove($fh);
> -
> -	if ($fh == $web_socket) {
> -	    if ($fh->connected) {
> -
> -		# close connection
> -		# Opcode, mask, statuscode
> -		my $msg = "\x88" . pack('N', 0) . pack('n', 0);
> -		$fh->syswrite($msg);
> -		close($fh);
> -	    }
> -	}
> -
> -    }
> -
> -    # switch back to blocking mode (else later shell commands will fail).
> -    STDIN->blocking(1);
> -
> -    #
> -    # Reset the terminal parameters.
> -    #
> -    print "\e[24H\r\n";
> -    PVE::PTY::tcsetattr(*STDIN, $old_termios);
> -};
> -
>  __PACKAGE__->register_method ({
>      name => 'enter',
>      path => 'enter',
> @@ -251,87 +222,90 @@ __PACKAGE__->register_method ({
>  	# Set STDIN to "raw -echo" mode
>  	my $old_termios = PVE::PTY::tcgetattr(*STDIN);
>  	my $raw_termios = {%$old_termios};
> -	PVE::PTY::cfmakeraw($raw_termios);
> -	PVE::PTY::tcsetattr(*STDIN, $raw_termios);
> -
> -	# And set it to non-blocking so we can every char with IO::Select.
> -	STDIN->blocking(0);
>  
>  	my $select = IO::Select->new;
>  
> -	$web_socket->blocking(0);
> -	$select->add($web_socket);
> -	$select->add(fileno(STDIN));
> +	eval {
> +	    $SIG{TERM} = $SIG{INT} = $SIG{KILL} = sub { die "received interrupt\n"; };
>  
> -	my @messages;
> -	my $ctrl_a_pressed_before = 0;
> -	my $next_ping = time() + 3;
> +	    PVE::PTY::cfmakeraw($raw_termios);
> +	    PVE::PTY::tcsetattr(*STDIN, $raw_termios);
>  
> -	eval {
> -	    while (1) {
> -		# Ping server every 3 seconds.
> -		my $now = time();
> -		if ($now >= $next_ping) {
> -		    push(@messages, $create_websockt_frame->("2"));
> -		    $next_ping = $now + 3;
> -		}
> +	    # And set it to non-blocking so we can every char with IO::Select.
> +	    STDIN->blocking(0);
>  
> -		# Write
> -		foreach my $fh ($select->can_write(0.5)) {
> -		    if ($fh == $web_socket and my $msg = shift @messages) {
> -			$fh->syswrite($msg, length($msg));
> -		    }
> -		}
> +	    $web_socket->blocking(1);

AFAIK this shouldn't be required, it's never set to non-blocking anymore
from what I can tell and this mode is the default anyway.

> +	    $select->add($web_socket);
> +	    my $input_fh = fileno(STDIN);
> +	    $select->add($input_fh);

This could have just been `$select->add(\*STDIN);`, no? ;-)

>  
> -		# Read
> -		foreach my $fh ($select->can_read(0.5)) {
> +	    my $ctrl_a_pressed_before = 0;
>  
> -		    # From Web Socket
> -		    if ($fh == $web_socket) {
> -			# Read from WebSocket
> -			my $nr = $wb_socket_read_available_bytes->();
> -			my ($payload, $req_close) = $parse_web_socket_frame->(\$wsbuf);
> +	    while (1) {
> +		while(my @ready = $select->can_read(3)) {
> +		    foreach my $fh (@ready) {
> +
> +			if ($fh == $web_socket) {
> +			    # Read from WebSocket
> +
> +			    my $nr = $wb_socket_read_available_bytes->();
> +			    if (!defined($nr)) {
> +				die "web socket read error $!\n";
> +			    } elsif ($nr == 0) {
> +				return; # EOF
> +			    } else {
> +				my ($payload, $req_close) = $parse_web_socket_frame->(\$wsbuf);
> +				if ($payload) {
> +				    syswrite(\*STDOUT, $payload);
> +				}
> +				return if $req_close;
> +			    }
>  
> -			if ($payload ne "OK") {
> -			    syswrite(\*STDOUT, $payload, length($payload));
> -			}
> -		    }
> +			} elsif ($fh == $input_fh) {
> +			    # Read from STDIN
>  
> -		    # From STDIN
> -		    elsif ($fh == fileno(STDIN)) {
> +			    my $nr = read(\*STDIN, my $buff, 4096);
> +			    return if !$nr; # EOF or error
>  
> -			# Read from STDIN
> -			my $nr = read(\*STDIN, my $buff, 4096);
> -			if (!$nr) {
> -			    next;
> -			}
> +			    my $char = ord($buff);
>  
> -			my $char = ord($buff);
> +			    # check for CTRL-a-q
> +			    return if $ctrl_a_pressed_before == 1 && $char == hex("0x71");
>  
> -			if ($ctrl_a_pressed_before == 1 && $char == hex("0x71")) {
> -			    $client_exit->($select, $web_socket, $old_termios);
> -			    return;
> -			}
> +			    $ctrl_a_pressed_before = ($char == hex("0x01") && $ctrl_a_pressed_before == 0) ? 1 : 0;
>  
> -			if ($char == hex("0x01")) {
> -			    if ($ctrl_a_pressed_before == 0) {
> -				$ctrl_a_pressed_before = 1;
> -			    }
> -			}
> -			else {
> -			    $ctrl_a_pressed_before = 0;
> +			    my $frame = $create_websockt_frame->("0:" . $nr . ":" . $buff);
> +			    syswrite($web_socket, $frame);
>  			}
> -
> -			push(@messages, $create_websockt_frame->("0:" . $nr . ":" . $buff));
>  		    }
>  		}
> +		# got timeout
> +		syswrite($web_socket, $create_websockt_frame->("2")); # ping server to keep connection alive
> +	    }
> +	};
> +	my $err = $@;
> +
> +	eval {  # cleanup
> +
> +	    # switch back to blocking mode (else later shell commands will fail).
> +	    STDIN->blocking(1);
> +
> +	    if ($web_socket->connected) {
> +		# close connection
> +		my $msg = "\x88" . pack('N', 0) . pack('n', 0); # Opcode, mask, statuscode
> +		$web_socket->syswrite($msg);
> +		close($web_socket);
>  	    }
> +
> +	    # Reset the terminal parameters.
> +	    syswrite(\*STDOUT, "\e[24H\r\n");
> +	    PVE::PTY::tcsetattr(*STDIN, $old_termios);
>  	};
> -	print "ERROR: " . $@ . ".\n" if $@;
> +	warn $@ if $@; # show cleanup errors
>  
> -	$client_exit->($select, $web_socket, $old_termios);
> +	print STDERR "\nERROR: $err" if $err;
>  
> -	return undef
> +	return undef;
>      }});
>  
>  __PACKAGE__->register_method ({
> -- 
> 2.11.0



More information about the pve-devel mailing list