]>
git.proxmox.com Git - pve-xtermjs.git/blob - src/PVE/CLI/termproxy.pm
3932f55e945859f4dda4d04ae41458fc371c08c0
1 package PVE
::CLI
::termproxy
;
6 use PVE
::RPCEnvironment
;
8 use PVE
::JSONSchema
qw(get_standard_option);
14 use base
qw(PVE::CLIHandler);
16 use constant MAX_QUEUE_LEN
=> 16*1024;
17 use constant DEFAULT_PATH
=> '/';
18 use constant DEFAULT_PERM
=> 'Sys.Console';
20 sub setup_environment
{
21 PVE
::RPCEnvironment-
>setup_default_cli_env();
25 my ($ticket, $user, $path, $perm) = @_;
27 my $ua = LWP
::UserAgent-
>new();
29 my $res = $ua->post ('http://localhost:85/api2/json/access/ticket', Content
=> {
35 if (!$res->is_success) {
36 die "Authentication failed: '$res->status_line'\n";
40 sub listen_and_authenticate
{
41 my ($port, $timeout, $path, $perm) = @_;
46 Proto
=> &Socket
::IPPROTO_TCP
,
47 GetAddrInfoFlags
=> 0,
48 LocalAddr
=> 'localhost',
52 my $socket = IO
::Socket
::IP-
>new(%$params) or die "failed to open socket: $!\n";
55 local $SIG{ALRM
} = sub { die "timed out waiting for client\n" };
57 my $client = $socket->accept; # Wait for a client
62 my $n = sysread($client, $queue, 4096);
63 if ($n && $queue =~ s/^([^:]+):(.+)\n//) {
67 verify_ticket
($ticket, $user, $path, $perm);
69 die "aknowledge failed\n"
70 if !syswrite($client, "OK");
73 die "malformed authentication string\n";
76 return ($queue, $client);
80 my ($cmd, $webhandle, $queue) = @_;
82 foreach my $k (keys %ENV) {
83 next if $k eq 'PATH' || $k eq 'USER' || $k eq 'HOME' || $k eq 'LANG' || $k eq 'LANGUAGE';
84 next if $k =~ m/^LC_/;
88 $ENV{TERM
} = 'xterm-256color';
90 my $pty = PVE
::PTY-
>new();
93 die "fork: $!\n" if !defined($pid);
95 $pty->make_controlling_terminal();
96 exec {$cmd->[0]} @$cmd
100 $pty->set_size(80,20);
102 read_write_loop
($webhandle, $pty->master, $queue, $pty);
109 sub read_write_loop
{
110 my ($webhandle, $cmdhandle, $queue, $pty) = @_;
112 my $select = new IO
::Select
;
114 $select->add($webhandle);
115 $select->add($cmdhandle);
119 # we may have already messages from the first read
120 $queue = process_queue
($queue, $cmdhandle, $pty);
124 while($select->count && scalar(@handles = $select->can_read($timeout))) {
125 foreach my $h (@handles) {
127 my $n = $h->sysread($buf, 4096);
129 if ($h == $webhandle) {
130 if ($n && (length($queue) + $n) < MAX_QUEUE_LEN
) {
131 $queue = process_queue
($queue.$buf, $cmdhandle, $pty);
135 } elsif ($h == $cmdhandle) {
137 syswrite($webhandle, $buf);
147 my ($queue, $handle, $pty) = @_;
150 while(length($queue)) {
151 ($queue, $msg) = remove_message
($queue, $pty);
152 last if !defined($msg);
153 syswrite($handle, $msg);
159 # we try to remove a whole message
160 # if we succeed, we return the remaining queue and the msg
161 # if we fail, the message is undef and the queue is not changed
163 my ($queue, $pty) = @_;
166 my $type = substr $queue, 0, 1;
170 my ($length) = $queue =~ m/^0:(\d+):/;
171 my $begin = 3 + length($length);
172 if (defined($length) && length($queue) >= ($length + $begin)) {
173 $msg = substr $queue, $begin, $length;
175 # msg contains now $length chars after 0:$length:
176 $queue = substr $queue, $begin + $length;
179 } elsif ($type eq '1') {
181 my ($cols, $rows) = $queue =~ m/^1:(\d+):(\d+):/;
182 if (defined($cols) && defined($rows)) {
183 $queue = substr $queue, (length($cols) + length ($rows) + 4);
184 eval { $pty->set_size($cols, $rows) if defined($pty) };
188 } elsif ($type eq '2') {
190 $queue = substr $queue, 1;
194 $queue = substr $queue, 1;
198 return ($queue, $msg);
201 __PACKAGE__-
>register_method ({
205 description
=> "Connects a TCP Socket with a commandline",
207 additionalProperties
=> 0,
211 description
=> "The port to listen on."
215 description
=> "The Authentication path. (default: '".DEFAULT_PATH
."')",
216 default => DEFAULT_PATH
,
220 description
=> "The Authentication Permission. (default: '".DEFAULT_PERM
."')",
221 default => DEFAULT_PERM
,
223 'extra-args' => get_standard_option
('extra-args'),
226 returns
=> { type
=> 'null'},
231 if (defined($param->{'extra-args'})) {
232 $cmd = [@{$param->{'extra-args'}}];
234 die "No command given\n";
237 my $path = $param->{path
} // DEFAULT_PATH
;
238 my $perm = $param->{perm
} // DEFAULT_PERM
;
239 my ($queue, $handle) = listen_and_authenticate
($param->{port
}, 10, $path, $perm);
241 run_pty
($cmd, $handle, $queue);
246 our $cmddef = [ __PACKAGE__
, 'exec', ['port', 'extra-args' ]];