Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

golf challenge: one-liner netcat clone

by salva (Canon)
on Dec 10, 2011 at 19:31 UTC ( [id://942861]=perlquestion: print w/replies, xml ) Need Help??

salva has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I am working on Net::OpenSSH::Gateway, a Net::OpenSSH extension that allows this module to cross through proxies and SSH gateways.

As part of it, I have written a Perl one-liner that is a netcat clone, but this one-liner is bigger than I wish, so I would like to get your help in order to reduce its length.

You can improve on the current version or rewrite it from scratch, I don't mind as long as it is able to run an SSH session on top of it (using ProxyCommand, see ssh_config) and exit when any side of the connection closes. It should only use core modules and be able to run on older Perls.

Here is the current one-liner:

perl -MFcntl=F_SETFL,F_GETFL,O_NONBLOCK -MSocket '-e$0=perl;socket($c, +AF_INET,SOCK_STREAM,0)&&connect($c,sockaddr_in$ARGV[1],inet_aton$ARGV +[0])||die$!;fcntl$_,F_SETFL,O_NONBLOCK|fcntl$_,F_GETFL,0 for@d=(*STDI +N,$c),@e=($c,*STDOUT);L:for(0,1){sysread($d[$_],$f,8**5)||exit and$f[ +$_].=$f if vec$g,$_*($h=fileno$c),1;substr$f[$_],0,syswrite($e[$_],$f +[$_],8**5),"";vec($g,$_*$h,1)=($i=length$f[$_]<8**5);vec($j,$_||$h,1) +=!!$i}select$g,$j,$k,5;goto L' perlmonks.org 80

It is automatically generated from this more readable version:

$0=perl; socket($socket, AF_INET, SOCK_STREAM, 0) && connect($socket, sockaddr_in PORT, inet_aton "SERVER") || die $!; fcntl $_, F_SETFL, O_NONBLOCK|fcntl $_, F_GETFL, 0 for @in = (*STDIN, +$socket), @out = ($socket, *STDOUT); L: for (0, 1) { sysread ($in[$_], $buffer, 8**5) || exit and $buffer[$_] .= $buffe +r if vec $iv, $_ * ($socket_fileno = fileno $socket), 1; substr $buffer[$_], 0, syswrite($out[$_], $buffer[$_], 8**5), ""; vec($iv, $_ * $socket_fileno, 1) = ($l = length $buffer[$_] < 8**5 +); vec($ov, $_ || $socket_fileno, 1) = !!$l; } select $iv, $ov, $u, 5; goto L

Replies are listed 'Best First'.
Re: golf challenge: one-liner netcat clone
by ikegami (Patriarch) on Dec 10, 2011 at 22:24 UTC

    I don't see a check to see how much can be written without blocking. You can have a write in one direction blocking writes in the other direction, which can lead to a deadlock.

    As for golfing, this bit:

    139: socket($c,AF_INET,SOCK_STREAM,0)&&connect($c,sockaddr_in$ARGV[1], +inet_aton$ARGV[0])||die$!;fcntl$_,F_SETFL,O_NONBLOCK|fcntl$_,F_GETFL, +0 for

    (whose only space is not needed) can be reduced to:

    100: -MIO::Socket::INET $c=IO::Socket::INET->new(PeerHost=>"$ARGV[0]:$ +ARGV[1]")||die$!;$_->blocking(0)for

    By the way, if you hardcoded the host and port, you could save a bunch more.

    Update:

    99: -MIO::Socket::INET $c=IO::Socket::INET->new(PeerHost,"$ARGV[0]:$A +RGV[1]")||die$!;$_->blocking(0)for 95: -MIO::Socket::INET $c=new IO::Socket::INET PeerHost,"$ARGV[0]:$AR +GV[1]"or die$!;blocking$_ 0for 85: -MIO::Socket::INET $c=new IO::Socket::INET"$ARGV[0]:$ARGV[1]"or d +ie$!;blocking$_ 0for
      $_->blocking(0) for *STDIN dies with a Can't call method "blocking" without a package or object reference

      On Linux, setting the sockets and pipes to non-blocking doesn't seem to be required at all, but I am not sure it other Unixes will perform the same.

        I take back my comment about write-blocking ("I don't see a check to see how much can be written without blocking"). I forgot to factor in that non-blocking applies to writing too.

        So you don't have a problem with syswrite, but you do have a problem with sysread. If the sysread would block, it'll return undef, and your program will exit prematurely.

        On Linux, setting the sockets and pipes to non-blocking doesn't seem to be required at all, but I am not sure it other Unixes will perform the same.

        Nonsense. Imagine if the remote end does

        print while <>;

        If you try reading from the socket, your program will become permanently blocked.

        Did you load the module as I did? (Although you don't even need to do that with 5.14)
Re: golf challenge: one-liner netcat clone
by cavac (Prior) on Dec 10, 2011 at 22:08 UTC

    Here's what i use to tunnel VNC sessions. Maybe it'll help. I'm not really a fan of one-liners, so i'll leave it in a readable form ;-)

    use POE; use POE::Filter::Stream; use POE::Filter::Line; use POE::Component::Proxy::TCP; $|++; POE::Component::Proxy::TCP->new (Alias => "ProxyServerSessionAlias", Port => $ARGV[1], OrigPort => $ARGV[2], OrigAddress => $ARGV[0], RemoteClientFilter => "POE::Filter::Stream", RemoteServerOutputFilter => "POE::Filter::Stream", RemoteServerInputFilter => "POE::Filter::Stream" ); $poe_kernel->run(); exit 0;

    Note: I don't fully understand the code (or more precise the workings of the POE:: stuff), i just copied it from various examples and modified it until it more or less worked. I *know* one shouldn't do that, but i was in a bit of hurry... And YES, it lacks strict and warnings. You wanted small code, right?

    Don't use '#ff0000':
    use Acme::AutoColor; my $redcolor = RED();
    All colors subject to change without notice.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://942861]
Approved by keszler
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2025-06-17 14:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.