#!/usr/bin/perl -w # A simple socket client that uses a two-handle wheel to pipe between # a socket and the console. It's hardcoded to talk with wheels.perl's # rot13 server on localhost port 32100. use strict; use lib '../lib'; use POSIX; BEGIN { die "This example uses the console, but $^O doesn't support select() on console handles, sorry." if $^O eq "MSWin32"; } use POE qw(Wheel::SocketFactory Wheel::ReadWrite Driver::SysRW Filter::Stream); my $rot13_port = 32100; #============================================================================== # A client socket session that pipes between a connected socket and # the console. It has two phases of operation: Connect phase, and # Interact phase. #------------------------------------------------------------------------------ # Start the session by trying to connect to a server. Create a # SocketFactory, then sit back until something occurs. sub session_start { my ($kernel, $heap, $connected_socket) = @_[KERNEL, HEAP, ARG0]; print "Connecting...\n"; $heap->{connector} = POE::Wheel::SocketFactory->new( RemoteAddress => '127.0.0.1', RemotePort => $rot13_port, SuccessEvent => 'connect_success', FailureEvent => 'connect_failure', ); } #------------------------------------------------------------------------------ # The connection succeeded. Discard the spent SocketFactory, and # start two ReadWrite wheels to pipe data back and forth. NOTE: This # doesn't do terminal characteristic games, so I/O may be choppy or # otherwise icky. sub session_connect_success { my ($heap, $kernel, $connected_socket) = @_[HEAP, KERNEL, ARG0]; delete $heap->{connector}; $heap->{console_wheel} = POE::Wheel::ReadWrite->new( InputHandle => \*STDIN, OutputHandle => \*STDOUT, Driver => POE::Driver::SysRW->new, Filter => POE::Filter::Stream->new, InputEvent => 'console_input', ErrorEvent => 'console_error', ); $heap->{socket_wheel} = POE::Wheel::ReadWrite->new( Handle => $connected_socket, Driver => POE::Driver::SysRW->new, Filter => POE::Filter::Stream->new, InputEvent => 'socket_input', ErrorEvent => 'socket_error', ); $heap->{console_wheel}->put("Begun terminal session."); } #------------------------------------------------------------------------------ # The connection failed. Close down everything so that POE will reap # the session and exit. sub session_connect_failure { my ($heap, $operation, $errnum, $errstr) = @_[HEAP, ARG0, ARG1, ARG2]; if ($errnum) { print "!!! Connecting: $operation error $errnum: $errstr\n"; } delete $heap->{connector}; delete $heap->{console_wheel}; delete $heap->{socket_wheel}; } #------------------------------------------------------------------------------ # The session has stopped. Delete the wheels once again, just for # redundancy's sake. sub session_stop { my $heap = $_[HEAP]; delete $heap->{connector}; delete $heap->{console_wheel}; delete $heap->{socket_wheel}; } #------------------------------------------------------------------------------ # Console input has arrived. Send it to the socket. sub session_console_input { $_[HEAP]->{socket_wheel}->put($_[ARG0]); } #------------------------------------------------------------------------------ # There has been an error on one of the console filehandles. Close # down everything so that POE will reap the session and exit. sub session_console_error { my ($heap, $operation, $errnum, $errstr) = @_[HEAP, ARG0, ARG1, ARG2]; if ($errnum) { print "!!! Console: $operation error $errnum: $errstr\n"; } delete $heap->{console_wheel}; delete $heap->{socket_wheel}; } #------------------------------------------------------------------------------ # Socket input has arrived. Send it to the console. sub session_socket_input { $_[HEAP]->{console_wheel}->put($_[ARG0]); } #------------------------------------------------------------------------------ # A socket error has occurred. Close down everything so that POE will # reap the session and exit. sub session_socket_error { my ($heap, $operation, $errnum, $errstr) = @_[HEAP, ARG0, ARG1, ARG2]; if ($errnum) { print "!!! Socket: $operation error $errnum: $errstr\n"; } delete $heap->{console_wheel}; delete $heap->{socket_wheel}; } #============================================================================== # Start the Session, which will fire off the _start event and begin # the connection. POE::Session->create( inline_states => { _start => \&session_start, _stop => \&session_stop, connect_success => \&session_connect_success, connect_failure => \&session_connect_failure, console_input => \&session_console_input, console_error => \&session_console_error, socket_input => \&session_socket_input, socket_error => \&session_socket_error, }, ); $poe_kernel->run(); exit;