#!/usr/local/bin/perl -w use strict ; use lib '../lib' ; use Stem::Event ; use Stem::Socket ; use Stem::AsyncIO ; use Time::HiRes qw( time ) ; use Getopt::Long ; my $opts_ok = GetOptions( \my %opts, 'upper_port=s', 'reverse_port=s', 'v|verbose', 'help|h', ) ; usage() unless $opts_ok ; usage() if $opts{help} ; my $time ; # this table defines the servers. each entry has the default port # number and the code to execute on the input data. my %servers = ( upper => { port => 8888, code => sub { uc $_[0] }, }, reverse => { port => 8889, code => sub { scalar( reverse $_[0] ) }, }, ) ; start_servers() ; Stem::Event::start_loop() ; exit ; sub start_servers { while( my( $id, $server ) = each %servers ) { # make each server entry an object bless $server, __PACKAGE__ ; # save its id in itself $server->{id} = $id ; # get the port from the options or the default my $port = $opts{"${id}_port"} || $server->{port} ; # get the listen socket and save it my $listen = Stem::Socket->new( object => $server, port => $port, server => 1, ) ; die "can't listen on $port: $listen" unless ref $listen ; $server->{listen} = $listen ; } } # this is called when a socket is connected sub connected { my( $server, $socket ) = @_ ; # create a session object. blessed directly into this class because it # is simple and works nicely my $self = bless { socket => $socket, id => $server->{id}, }, __PACKAGE__ ; # get an asyncio object and save it in the session object # this will buffer all input and send it only when the socket is closed my $async = Stem::AsyncIO->new( object => $self, fh => $socket, send_data_on_close => 1, ) ; ref $async or die "can't create Async: $async" ; $self->{async} = $async ; } # this is called when we have read data sub async_read_data { my( $self, $data ) = @_ ; # print "READ [$$data]\n" ; # save (the ref to) the data $self->{'data'} = $data ; # get a random delay time # my $delay = .5 ; my $delay = rand( 1 ) + .5 ; $delay = .01 ; #print "DELAY $delay\n" ; $time = time() ; # get and save a timer object with this delay my $timer = Stem::Event::Timer->new( object => $self, delay => $delay, ) ; ref $timer or die "can't create Timer: $timer" ; $self->{timer} = $timer ; return ; } # timeout is over so this gets called sub timed_out { my( $self ) = @_ ; # my $delta = time() - $time ; # printf "DELTA = %6f\n", $delta ; # get the real datat my $data = ${$self->{data}}; # find the server (we could have saved this in the session object but # we can do this quick lookup to get it) my $server = $servers{ $self->{'id'} } ; # process the input data with the code in the server object my $echo_data = $server->{code}->( $data ) ; # print "ECHO [$echo_data]\n" ; # write out the echo data to the socket and close it when done. $self->{async}->final_write( $echo_data ) ; } sub usage { my ( $error ) = @_ ; $error ||= '' ; die <] [--reverse_port ] upper_port Set the port for the upper case server (default is 8888) reverse_port Set the port for the string reverse server (default is 8889) help | h Print this help text DIE } # sub async_closed { # my( $self ) = @_ ; # print "CLOSED $self\n" ; # } # DESTROY { # my( $self ) = @_ ; # print "DESTROY $self\n" ; # }