###########################################
# POE Port Forwarder
# Mike Schilli, 2010 (m@perlmeister.com)
###########################################
package PoCoForwarder;
use strict;
use Log::Log4perl qw(:easy);
use POE::Component::Server::TCP;
use POE::Component::Client::TCP;
use POE;

###########################################
sub new {
###########################################
  my($class, %options) = @_;

  my $self = { %options };

  my $server_session =
  POE::Component::Server::TCP->new(
    ClientArgs     => [$self],
    Port           => $self->{port_from},
    ClientConnected  => \&client_connect,
    ClientInput      => \&client_request,
    Started          => sub {
      $self->{port_bound}->(@_) if
        defined $self->{port_bound};
    },
  );

  return bless $self, $class;
}

###########################################
sub client_connect {
###########################################
  my ($kernel, $heap, $session, $self) = 
          @_[ KERNEL, HEAP, SESSION, ARG0];

  $self->{client_connect}->(@_) if
    defined $self->{client_connect};

  my $client_session = 
  POE::Component::Client::TCP->new(
    RemoteAddress => "localhost",
    RemotePort    => $self->{port_to},
    ServerInput   => sub {
      my $input = $_[ARG0];
        # $heap is the tcpserver's (!) heap
      $heap->{client}->put( $_[ARG0] );
    },
    Connected => sub { 
        $_[HEAP]->{connected} = 1; },
    Disconnected => sub {
     $kernel->post( $session, "shutdown" );
    },
    ConnectError => sub {
     $_[HEAP]->{connected} = 0;
     $kernel->delay('reconnect', 1);
    },
    ServerError => sub {
     ERROR $_[ARG0] if $_[ARG1];
     $kernel->post( $session, "shutdown" );
    },
  );

  $heap->{client_heap} = $kernel->
    ID_id_to_session( $client_session )->
    get_heap();
}

###########################################
sub client_request {
###########################################
  my ($kernel, $heap, $request) = 
     @_[ KERNEL, HEAP, ARG0 ];

  return if  # tunnel not up yet, discard
    ! $heap->{client_heap}->{connected};

  $heap->{client_heap}->
         {server}->put( $request );
}

1;
