Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

socket- and pseudo-tty-problem

146 views
Skip to first unread message

Michael Pradel

unread,
Mar 21, 2003, 6:46:24 AM3/21/03
to
Hi,

i am writing a kind of remote shell. Therefore a pseudo-tty is created with IO::Pty on the remote machine. In it the bash is started.
Its output should be sent to the local machine using a tcp-connection.
In the other direction, the local STDIN should be sent to the remote machine, which gives it to the pseudo-tty.

That's my approach (sorry for the length):


client.pl:
----------

#!/usr/bin/perl -w
use strict;
use IO::Socket;
use Term::ReadKey;

my ($host, $port, $handle);

$host = "localhost";
$port = 1234;

$handle = IO::Socket::INET->new (
Proto => "tcp",
PeerAddr => $host,
PeerPort => $port)
or die "Could not connect to $host on Port $port: $!";

$handle->autoflush();

print STDERR "[Connected with $host:$port]\n";

defined (my $child = fork()) or die "Could not fork: $!";
my $char;
ReadMode(4);
if ($child) {
while (defined($char = getc($handle))) {
print STDOUT $char;
}
} else {
while (defined($char = getc(STDIN))) {
print $handle $char;
}
}


#############################


server.pl:
----------

#!/usr/bin/perl -w
use strict;
use IO::Pty;
use IO::Socket;
use POSIX 'setsid';
use Term::ReadKey;

my $server_port = "1234";
my $server_address = "localhost";

my $server = IO::Socket::INET->new(
LocalPort => $server_port,
LocalAddr => $server_address,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 5)
or die "Cannot be a server on $server_port: $@\n";

my $client = $server->accept();

sub do_cmd {
my ($cmd, @args) = @_;
my $pty = IO::Pty->new or die "Could not create pty: $!";
defined (my $child = fork) or die "Could not fork: $!";
return $pty if $child;

POSIX::setsid();
my $tty = $pty->slave;
close $pty;

STDIN->fdopen($tty, "<") or die "STDIN: $!";
STDOUT->fdopen($tty, ">") or die "STDOUT: $!";
STDERR->fdopen(\*STDOUT, ">") or die "STDERR: $!";
close $tty;
$| = 1;
exec $cmd, @args;
die "Could not execute program: $!";
}

my $bash = do_cmd('bash');
defined (my $child = fork()) or die "Could not fork: $!";
my $char;
ReadMode(4);
if ($child) {
while (defined($char = getc($bash))) {
print $client $char;
}
} else {
while (defined($zeichen = getc($client))) {
print $bash $zeichen;
}
}


##########################

For testing you first have to start server.pl and after that client.pl.

As you can (hopefully) see, it doesn't work really good. E.g. you have to press enter to see the first output (like user@hostname:~$) and using the mc you also have to press enter a lot of times when it shouldn't be necessary.

I am happy about any ideas how it could work correctly. Thank you.


Michael Pradel.

Rocco Caputo

unread,
Mar 23, 2003, 9:11:04 PM3/23/03
to
On Fri, 21 Mar 2003 12:46:24 +0100, Michael Pradel wrote:
> Hi,
>
> i am writing a kind of remote shell. Therefore a pseudo-tty is created with IO::Pty on the remote machine. In it the bash is started.
> Its output should be sent to the local machine using a tcp-connection.
> In the other direction, the local STDIN should be sent to the remote machine, which gives it to the pseudo-tty.
>
> That's my approach (sorry for the length):

[...]

> For testing you first have to start server.pl and after that client.pl.
>
> As you can (hopefully) see, it doesn't work really good. E.g. you have to press enter to see the first output (like user@hostname:~$) and using the mc you also have to press enter a lot of times when it shouldn't be necessary.
>
> I am happy about any ideas how it could work correctly. Thank you.

I think your terminal is probably in canonical mode. This means input
is processed by line, not character, so getc() only begins to read
characters once EOL is received.

2) eyrie:~% perl -wle 'while (1) { print ord getc(STDIN) }'
input
105
110
112
117
116
10
^C

There are ways to turn off canonical mode. Read about stty(1) and the
POSIX module.

There are programs to do this already. I have written one, and it's
available at http://poe.perl.org/?POE_Cookbook/Job_Server

Finally, you're in for a world of hurt if you let anyone with a telnet
client run a shell on your machine. Seriously consider using sshd
instead.

-- Rocco Caputo - tr...@pobox.com - http://poe.perl.org/

Michael Pradel

unread,
Mar 24, 2003, 2:53:52 PM3/24/03
to
> I think your terminal is probably in canonical mode. This means input
> is processed by line, not character, so getc() only begins to read
> characters once EOL is received.
>
> 2) eyrie:~% perl -wle 'while (1) { print ord getc(STDIN) }'
> input
> 105
> 110
> 112
> 117
> 116
> 10
> ^C
>
> There are ways to turn off canonical mode. Read about stty(1) and the
> POSIX module.

I use 'ReadMode(4)' from the module Term::Readkey. This should set the
terminal in 'raw mode'. I also tried 'ReadMode(3)', which means 'cbreak
mode'. I thought both are non-canonical (?).

I also tried it with a 'system("stty -icanon")' instead, but it also
didn't work.

Any other ideas?

> Finally, you're in for a world of hurt if you let anyone with a telnet
> client run a shell on your machine. Seriously consider using sshd
> instead.

Oh yes - i know. That's only for testing.

0 new messages