POE and Port Redirection

Discussion in 'Perl Misc' started by Theo James, Sep 18, 2004.

  1. Theo James

    Theo James Guest

    Bear with me folks, I have been working with POE for about 60 minutes.
    I am in need of a port redirector that works like this:

    Client -> Server -> Host

    The client will create many session on the same port on the Server.
    For each connection, the server needs to create a redirection on one
    of 20 predefined ports to the Host (call it 9600-9619). The
    connections will last less than 2 seconds each and if all 20 sessions
    are in use, the servers port (call it 6666) needs to be block.

    I found some code and tweaked it a bit to get a single port to
    redirect, but I am at a loss from where to from here. Any help would
    be appreciated:

    #!/usr/bin/perl -Tw
    use warnings;
    use strict;
    use Socket;
    use POSIX qw(errno_h);

    # Import POE and the extra modules we'll need within it.

    use POE qw( Wheel::ReadWrite Wheel::SocketFactory Filter::Stream );

    # The redirection table.

    my %redirects =
    qw( 1.6.20.15:6666 12.1.2.135:6666
    );

    ### This is a stream-based tcp forwarder session. It passes data
    ### between two sockets, and that's about all.

    # Create a session that will forward data between two sockets.

    sub forwarder_create {
    my ( $handle, $peer_host, $peer_port, $remote_addr, $remote_port )
    = @_;

    POE::Session->new
    ( _start => \&forwarder_start,
    _stop => \&forwarder_stop,
    client_input => \&forwarder_client_input, # Client sent
    something.
    client_error => \&forwarder_client_error, # Error on
    client socket.
    server_connect => \&forwarder_server_connect, # Connected to
    server.
    server_input => \&forwarder_server_input, # Server sent
    something.
    server_error => \&forwarder_server_error, # Error on
    server socket.

    # Pass some things to forwarder_start():
    # ARG0, ARG1, ARG2, ARG3, ARG4
    [ $handle, $peer_host, $peer_port, $remote_addr, $remote_port
    ]
    );
    }


    sub forwarder_start {
    my ( $heap, $session,
    $socket, $peer_host, $peer_port, $remote_addr, $remote_port
    ) =
    @_[ HEAP, SESSION,
    ARG0, ARG1, ARG2, ARG3, ARG4
    ];

    $heap->{log} = $session->ID;
    $peer_host = inet_ntoa($peer_host);
    $heap->{peer_host} = $peer_host;
    $heap->{peer_port} = $peer_port;
    $heap->{remote_addr} = $remote_addr;
    $heap->{remote_port} = $remote_port;

    print "[$heap->{log}] Accepted connection from
    $peer_host:$peer_port\n";

    $heap->{state} = 'connecting';
    $heap->{queue} = [];

    $heap->{wheel_client} = POE::Wheel::ReadWrite->new
    ( Handle => $socket,
    Driver => POE::Driver::SysRW->new,
    Filter => POE::Filter::Stream->new,
    InputEvent => 'client_input',
    ErrorEvent => 'client_error',
    );

    $heap->{wheel_server} = POE::Wheel::SocketFactory->new
    ( RemoteAddress => $remote_addr,
    RemotePort => $remote_port,
    SuccessEvent => 'server_connect',
    FailureEvent => 'server_error',
    );
    }

    # The forwarder has stopped. Log that it's done.

    sub forwarder_stop {
    my $heap = $_[HEAP];
    print "[$heap->{log}] Closing redirection session\n";
    }

    # The forwarder has received data from its client side. Pass the data
    # through to the server if it's connected. Otherwise hold the data in
    # a queue until the server connects.

    sub forwarder_client_input {
    my ( $heap, $input ) = @_[ HEAP, ARG0 ];

    if ( $heap->{state} eq 'connecting' ) {
    push @{ $heap->{queue} }, $input;
    }
    else {
    ( exists $heap->{wheel_server} ) &&
    $heap->{wheel_server}->put($input);
    }
    }

    # The forwarder has received an error from the client. Shut down both
    # sides of the connection. Log the error in a manner appropriate to
    # its type.

    sub forwarder_client_error {
    my ( $kernel, $heap, $operation, $errnum, $errstr ) =
    @_[ KERNEL, HEAP, ARG0, ARG1, ARG2 ];

    if ($errnum) {
    print( "[$heap->{log}] Client connection encountered ",
    "$operation error $errnum: $errstr\n"
    );
    }
    else {
    print "[$heap->{log}] Client closed connection.\n";
    }

    delete $heap->{wheel_client};
    delete $heap->{wheel_server};
    }

    # The forwarder's SocketFactory has successfully connected to the
    # server. Log the success, and create a ReadWrite wheel to interact
    # with the server socket. If the client sent anything during the
    # connection process, pass it through to the server now.

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

    my ( $local_port, $local_addr ) = unpack_sockaddr_in(
    getsockname($socket) );
    $local_addr = inet_ntoa($local_addr);
    print( "[$heap->{log}] Established forward from local ",
    "$local_addr:$local_port to remote ",
    $heap->{remote_addr}, ':', $heap->{remote_port}, "\n"
    );

    # Replace the SocketFactory wheel with a ReadWrite wheel.

    $heap->{wheel_server} = POE::Wheel::ReadWrite->new
    ( Handle => $socket,
    Driver => POE::Driver::SysRW->new,
    Filter => POE::Filter::Stream->new,
    InputEvent => 'server_input',
    ErrorEvent => 'server_error',
    );

    $heap->{state} = 'connected';
    foreach my $pending ( @{ $heap->{queue} } ) {
    $kernel->call( $session, 'client_input', $pending );
    }
    $heap->{queue} = [];
    }

    # The forwarder has received data from its server side. Pass that
    # through to the client.

    sub forwarder_server_input {
    my ( $heap, $input ) = @_[ HEAP, ARG0 ];

    exists( $heap->{wheel_client} ) and
    $heap->{wheel_client}->put($input);
    }

    # The forwarder has received an error from the server. Shut down both
    # sides of the connection. Log the error in a manner appropriate to
    # its type.

    sub forwarder_server_error {
    my ( $kernel, $heap, $operation, $errnum, $errstr ) =
    @_[ KERNEL, HEAP, ARG0, ARG1, ARG2 ];

    if ($errnum) {
    print( "[$heap->{log}] Server connection encountered ",
    "$operation error $errnum: $errstr\n"
    );
    }
    else {
    print "[$heap->{log}] Server closed connection.\n";
    }

    delete $heap->{wheel_client};
    delete $heap->{wheel_server};
    }

    ### This is a stream-based forwarder server. It listens on TCP ports,
    ### and it spawns new forwarders to redirect incoming connections.

    # Create a session that acts as the forwarder server.

    sub server_create {
    my ( $local_address, $local_port, $remote_address, $remote_port )
    = @_;

    POE::Session->new
    ( _start => \&server_start,
    _stop => \&server_stop,
    accept_success => \&server_accept_success,
    accept_failure => \&server_accept_failure,

    # Pass this function's parameters to the server_start().
    # ARG0, ARG1, ARG2, ARG3
    [ $local_address, $local_port, $remote_address, $remote_port ]
    );
    }

    # Start the server. This records where the server should connect, and
    # it creates the listening socket factory.

    sub server_start {
    my ( $heap, $local_addr, $local_port, $remote_addr, $remote_port )
    =
    @_[ HEAP, ARG0, ARG1, ARG2, ARG3 ];

    print "+ Redirecting $local_addr:$local_port to
    $remote_addr:$remote_port\n";

    $heap->{local_addr} = $local_addr;
    $heap->{local_port} = $local_port;
    $heap->{remote_addr} = $remote_addr;
    $heap->{remote_port} = $remote_port;

    $heap->{server_wheel} = POE::Wheel::SocketFactory->new
    ( BindAddress => $local_addr, # bind to this address
    BindPort => $local_port, # and bind to this port
    Reuse => 'yes', # reuse immediately
    SuccessEvent => 'accept_success', # generate this event on
    connection
    FailureEvent => 'accept_failure', # generate this event on
    error
    );
    }

    # The server is stopping. Log that fact.

    sub server_stop {
    my $heap = $_[HEAP];
    print( "- Redirection from $heap->{local_addr}:$heap->{local_port}
    to ",
    "$heap->{remote_addr}:$heap->{remote_port} has stopped.\n"
    );
    }

    # The server has accepted a client connection. Pass the details about
    # it to the function that creates a new forwarder. This is as
    # unnecessary step. The contents of forwarder_create() could have
    # been placed directly into server_accept_success().

    sub server_accept_success {
    my ( $heap, $socket, $peer_addr, $peer_port ) = @_[ HEAP, ARG0,
    ARG1, ARG2 ];
    &forwarder_create( $socket, $peer_addr, $peer_port,
    $heap->{remote_addr}, $heap->{remote_port}
    );
    }

    # The server encountered an error. Log the error. If we've run out
    # of file descriptors, we'll have to shut down the server. A serious
    # port redirector should just restart the server here.

    sub server_accept_failure {
    my ( $heap, $operation, $errnum, $errstr ) = @_[ HEAP, ARG0, ARG1,
    ARG2 ];

    print( "! Redirection from $heap->{local_addr}:$heap->{local_port}
    to ",
    "$heap->{remote_addr}:$heap->{remote_port} encountered
    $operation ",
    "error $errnum: $errstr\n"
    );

    delete $heap->{server_wheel} if $errnum == ENFILE or $errnum ==
    EMFILE;
    }

    ### Main loop. Create a new server for each record in %redirects.
    ### Run POE until all the servers (and their forwarders) shut down.

    while ( my ( $from, $to ) = each %redirects ) {
    my ( $from_address, $from_port ) = split ( /:/, $from );
    my ( $to_address, $to_port ) = split ( /:/, $to );

    &server_create( $from_address, $from_port, $to_address, $to_port
    );
    }

    $poe_kernel->run();
     
    Theo James, Sep 18, 2004
    #1
    1. Advertising

  2. Theo James

    Rocco Caputo Guest

    On 17 Sep 2004 20:29:09 -0700, Theo James wrote:
    > Bear with me folks, I have been working with POE for about 60 minutes.
    > I am in need of a port redirector that works like this:
    >
    > Client -> Server -> Host
    >
    > The client will create many session on the same port on the Server.
    > For each connection, the server needs to create a redirection on one
    > of 20 predefined ports to the Host (call it 9600-9619). The
    > connections will last less than 2 seconds each and if all 20 sessions
    > are in use, the servers port (call it 6666) needs to be block.
    >
    > I found some code and tweaked it a bit to get a single port to
    > redirect, but I am at a loss from where to from here. Any help would
    > be appreciated:


    Here's a version that accepts connections on one port and forwards them to a
    range of ports on another machine. It's untested, but I have verified that it
    passes "perl -T -c".

    --
    Rocco Caputo - http://poe.perl.org/

    #!/usr/bin/perl -Tw

    use warnings;
    use strict;

    use Socket;
    use POSIX qw(errno_h);

    # Import POE and the extra modules we'll need within it.

    use POE qw( Wheel::ReadWrite Wheel::SocketFactory Filter::Stream );

    # Some aspects of redirection.

    use constant LOCAL_ADDRESS => "1.6.20.15";
    use constant LOCAL_PORT => 6666;
    use constant REMOTE_ADDRESS => "12.1.2.135";

    my @open_redirects = (9600..9619);

    # Create a session that will forward data between two sockets.

    sub forwarder_create {
    my ($handle, $port) = @_;

    POE::Session->create(
    inline_states => {
    _start => \&forwarder_start,
    _stop => \&forwarder_stop,
    client_input => \&forwarder_client_input,
    error => \&forwarder_error,
    server_connect => \&forwarder_server_connect,
    server_input => \&forwarder_server_input,
    },
    args => [ $handle, $port ]
    );
    }

    # The forwarder is actually starting. Begin interacting with the
    # client, and begin connecting to the server.

    sub forwarder_start {
    my ($heap, $socket, $remote_port) = @_[HEAP, ARG0, ARG1];

    $heap->{state} = 'connecting';
    $heap->{queue} = [];
    $heap->{port} = $remote_port;

    $heap->{wheel_client} = POE::Wheel::ReadWrite->new(
    Handle => $socket,
    Filter => POE::Filter::Stream->new,
    InputEvent => 'client_input',
    ErrorEvent => 'error',
    );

    $heap->{wheel_server} = POE::Wheel::SocketFactory->new(
    RemoteAddress => REMOTE_ADDRESS,
    RemotePort => $remote_port,
    SuccessEvent => 'server_connect',
    FailureEvent => 'error',
    );
    }

    # The forwarder has stopped. Put its port at the end of the open
    # redirects list so it can be reused.

    sub forwarder_stop {
    push @open_redirects, $_[HEAP]->{port};
    }

    # The forwarder has received data from its client side. Queue the
    # data if the server connection hasn't been established yet.
    # Otherwise send it through to the server.

    sub forwarder_client_input {
    my ( $heap, $input ) = @_[ HEAP, ARG0 ];

    if ( $heap->{state} eq 'connecting' ) {
    push @{ $heap->{queue} }, $input;
    return;
    }

    return unless exists $heap->{wheel_server};
    $heap->{wheel_server}->put($input);
    }

    # A server connection was successfully made. Send any pending data to
    # it.

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

    # Replace the SocketFactory wheel with a ReadWrite wheel, so we can
    # interact with the server.

    $heap->{wheel_server} = POE::Wheel::ReadWrite->new(
    Handle => $socket,
    Filter => POE::Filter::Stream->new,
    InputEvent => 'server_input',
    ErrorEvent => 'server_error',
    );

    # Send pending data to the server.
    if (@{$heap->{queue}}) {
    $heap->{wheel_server}->put( @{$heap->{queue}} );
    $heap->{queue} = [];
    }
    }

    # The forwarder has received data from its server side. Pass that
    # through to the client.

    sub forwarder_server_input {
    my ( $heap, $input ) = @_[ HEAP, ARG0 ];
    return unless exists $heap->{wheel_client};
    $heap->{wheel_client}->put($input);
    }

    # The forwarder has received an error from either the client or
    # server. Shut it all down.

    sub forwarder_error {
    my $heap = $_[HEAP];
    delete $heap->{wheel_client};
    delete $heap->{wheel_server};
    }

    ###--------------------------------------------------------------
    ### This is the listening part of the redirector.

    # Create a session that acts as the forwarder server.

    sub server_create {
    POE::Session->new(
    _start => \&server_start,
    _child => \&forwarder_status,
    accept_success => \&server_accept_success,
    accept_failure => \&server_accept_failure,
    );
    }

    # Start the server.

    sub server_start {
    my $heap = $_[HEAP];

    $heap->{server_wheel} = POE::Wheel::SocketFactory->new(
    BindAddress => LOCAL_ADDRESS,
    BindPort => LOCAL_PORT,
    Reuse => 'yes',
    SuccessEvent => 'accept_success',
    FailureEvent => 'accept_failure',
    );
    }

    # The status of a forwarder has changed. If a forwarder is going
    # away, it means we have one more redirect port open. Check to see if
    # the server should resume accepting connections.

    sub forwarder_status {
    my $op = $_[ARG0];
    return unless $op eq "lose";
    $_[HEAP]->resume_accept() if @open_redirects == 1;
    }

    # The server has accepted a client connection. Start forwarding.

    sub server_accept_success {
    my ( $heap, $socket, $peer_addr, $peer_port ) = @_[ HEAP, ARG0, ARG1, ARG2 ];

    # Grab the next open redirect port in our list.
    my $next_remote_port = shift @open_redirects;
    forwarder_create($socket, $next_remote_port);

    # Temporarily stop accepting connections if there are no more
    # redirect ports.
    $heap->{server_wheel}->pause_accept() unless @open_redirects;
    }

    # The server encountered an error. Shut it down if we've run out of
    # file descriptiors. A serious port redirector would handle this more
    # gracefully.

    sub server_accept_failure {
    my ( $heap, $operation, $errnum, $errstr ) = @_[ HEAP, ARG0, ARG1, ARG2 ];
    delete $heap->{server_wheel} if $errnum == ENFILE or $errnum == EMFILE;
    }

    # Main loop. Create a single listening socket that redirects
    # connections to one of a pool of remote sockets.

    server_create();
    POE::Kernel->run;
    exit;
     
    Rocco Caputo, Sep 18, 2004
    #2
    1. Advertising

  3. Theo James

    Theo James Guest

    Thanks for the quick response. I have placed it on my Linux box and
    am trying it out now!

    --Theo

    Rocco Caputo <> wrote in message news:<>...
    > On 17 Sep 2004 20:29:09 -0700, Theo James wrote:
    > > Bear with me folks, I have been working with POE for about 60 minutes.
    > > I am in need of a port redirector that works like this:
    > >
    > > Client -> Server -> Host
    > >
    > > The client will create many session on the same port on the Server.
    > > For each connection, the server needs to create a redirection on one
    > > of 20 predefined ports to the Host (call it 9600-9619). The
    > > connections will last less than 2 seconds each and if all 20 sessions
    > > are in use, the servers port (call it 6666) needs to be block.
    > >
    > > I found some code and tweaked it a bit to get a single port to
    > > redirect, but I am at a loss from where to from here. Any help would
    > > be appreciated:

    >
    > Here's a version that accepts connections on one port and forwards them to a
    > range of ports on another machine. It's untested, but I have verified that it
    > passes "perl -T -c".
    >
    > --
    > Rocco Caputo - http://poe.perl.org/
    >
    > #!/usr/bin/perl -Tw
    >
    > use warnings;
    > use strict;
    >
    > use Socket;
    > use POSIX qw(errno_h);
    >
    > # Import POE and the extra modules we'll need within it.
    >
    > use POE qw( Wheel::ReadWrite Wheel::SocketFactory Filter::Stream );
    >
    > # Some aspects of redirection.
    >
    > use constant LOCAL_ADDRESS => "1.6.20.15";
    > use constant LOCAL_PORT => 6666;
    > use constant REMOTE_ADDRESS => "12.1.2.135";
    >
    > my @open_redirects = (9600..9619);
    >
    > # Create a session that will forward data between two sockets.
    >
    > sub forwarder_create {
    > my ($handle, $port) = @_;
    >
    > POE::Session->create(
    > inline_states => {
    > _start => \&forwarder_start,
    > _stop => \&forwarder_stop,
    > client_input => \&forwarder_client_input,
    > error => \&forwarder_error,
    > server_connect => \&forwarder_server_connect,
    > server_input => \&forwarder_server_input,
    > },
    > args => [ $handle, $port ]
    > );
    > }
    >
    > # The forwarder is actually starting. Begin interacting with the
    > # client, and begin connecting to the server.
    >
    > sub forwarder_start {
    > my ($heap, $socket, $remote_port) = @_[HEAP, ARG0, ARG1];
    >
    > $heap->{state} = 'connecting';
    > $heap->{queue} = [];
    > $heap->{port} = $remote_port;
    >
    > $heap->{wheel_client} = POE::Wheel::ReadWrite->new(
    > Handle => $socket,
    > Filter => POE::Filter::Stream->new,
    > InputEvent => 'client_input',
    > ErrorEvent => 'error',
    > );
    >
    > $heap->{wheel_server} = POE::Wheel::SocketFactory->new(
    > RemoteAddress => REMOTE_ADDRESS,
    > RemotePort => $remote_port,
    > SuccessEvent => 'server_connect',
    > FailureEvent => 'error',
    > );
    > }
    >
    > # The forwarder has stopped. Put its port at the end of the open
    > # redirects list so it can be reused.
    >
    > sub forwarder_stop {
    > push @open_redirects, $_[HEAP]->{port};
    > }
    >
    > # The forwarder has received data from its client side. Queue the
    > # data if the server connection hasn't been established yet.
    > # Otherwise send it through to the server.
    >
    > sub forwarder_client_input {
    > my ( $heap, $input ) = @_[ HEAP, ARG0 ];
    >
    > if ( $heap->{state} eq 'connecting' ) {
    > push @{ $heap->{queue} }, $input;
    > return;
    > }
    >
    > return unless exists $heap->{wheel_server};
    > $heap->{wheel_server}->put($input);
    > }
    >
    > # A server connection was successfully made. Send any pending data to
    > # it.
    >
    > sub forwarder_server_connect {
    > my ( $kernel, $session, $heap, $socket ) = @_[ KERNEL, SESSION, HEAP, ARG0 ];
    >
    > # Replace the SocketFactory wheel with a ReadWrite wheel, so we can
    > # interact with the server.
    >
    > $heap->{wheel_server} = POE::Wheel::ReadWrite->new(
    > Handle => $socket,
    > Filter => POE::Filter::Stream->new,
    > InputEvent => 'server_input',
    > ErrorEvent => 'server_error',
    > );
    >
    > # Send pending data to the server.
    > if (@{$heap->{queue}}) {
    > $heap->{wheel_server}->put( @{$heap->{queue}} );
    > $heap->{queue} = [];
    > }
    > }
    >
    > # The forwarder has received data from its server side. Pass that
    > # through to the client.
    >
    > sub forwarder_server_input {
    > my ( $heap, $input ) = @_[ HEAP, ARG0 ];
    > return unless exists $heap->{wheel_client};
    > $heap->{wheel_client}->put($input);
    > }
    >
    > # The forwarder has received an error from either the client or
    > # server. Shut it all down.
    >
    > sub forwarder_error {
    > my $heap = $_[HEAP];
    > delete $heap->{wheel_client};
    > delete $heap->{wheel_server};
    > }
    >
    > ###--------------------------------------------------------------
    > ### This is the listening part of the redirector.
    >
    > # Create a session that acts as the forwarder server.
    >
    > sub server_create {
    > POE::Session->new(
    > _start => \&server_start,
    > _child => \&forwarder_status,
    > accept_success => \&server_accept_success,
    > accept_failure => \&server_accept_failure,
    > );
    > }
    >
    > # Start the server.
    >
    > sub server_start {
    > my $heap = $_[HEAP];
    >
    > $heap->{server_wheel} = POE::Wheel::SocketFactory->new(
    > BindAddress => LOCAL_ADDRESS,
    > BindPort => LOCAL_PORT,
    > Reuse => 'yes',
    > SuccessEvent => 'accept_success',
    > FailureEvent => 'accept_failure',
    > );
    > }
    >
    > # The status of a forwarder has changed. If a forwarder is going
    > # away, it means we have one more redirect port open. Check to see if
    > # the server should resume accepting connections.
    >
    > sub forwarder_status {
    > my $op = $_[ARG0];
    > return unless $op eq "lose";
    > $_[HEAP]->resume_accept() if @open_redirects == 1;
    > }
    >
    > # The server has accepted a client connection. Start forwarding.
    >
    > sub server_accept_success {
    > my ( $heap, $socket, $peer_addr, $peer_port ) = @_[ HEAP, ARG0, ARG1, ARG2 ];
    >
    > # Grab the next open redirect port in our list.
    > my $next_remote_port = shift @open_redirects;
    > forwarder_create($socket, $next_remote_port);
    >
    > # Temporarily stop accepting connections if there are no more
    > # redirect ports.
    > $heap->{server_wheel}->pause_accept() unless @open_redirects;
    > }
    >
    > # The server encountered an error. Shut it down if we've run out of
    > # file descriptiors. A serious port redirector would handle this more
    > # gracefully.
    >
    > sub server_accept_failure {
    > my ( $heap, $operation, $errnum, $errstr ) = @_[ HEAP, ARG0, ARG1, ARG2 ];
    > delete $heap->{server_wheel} if $errnum == ENFILE or $errnum == EMFILE;
    > }
    >
    > # Main loop. Create a single listening socket that redirects
    > # connections to one of a pool of remote sockets.
    >
    > server_create();
    > POE::Kernel->run;
    > exit;
     
    Theo James, Sep 19, 2004
    #3
  4. The POE is very powerful. But i have some question about it.
    Is the POE applicable for do this job??
    If i have 100 concurrent connection to do this job .
    Example 211.11.22.31:389 211.11.22.32 389


    How to do POE benchmark for this situation?



    "Rocco Caputo" <> ¦b¶l¥ó
    news: ¤¤¼¶¼g...
    > On 17 Sep 2004 20:29:09 -0700, Theo James wrote:
    > > Bear with me folks, I have been working with POE for about 60 minutes.
    > > I am in need of a port redirector that works like this:
    > >
    > > Client -> Server -> Host
    > >
    > > The client will create many session on the same port on the Server.
    > > For each connection, the server needs to create a redirection on one
    > > of 20 predefined ports to the Host (call it 9600-9619). The
    > > connections will last less than 2 seconds each and if all 20 sessions
    > > are in use, the servers port (call it 6666) needs to be block.
    > >
    > > I found some code and tweaked it a bit to get a single port to
    > > redirect, but I am at a loss from where to from here. Any help would
    > > be appreciated:

    >
    > Here's a version that accepts connections on one port and forwards them to

    a
    > range of ports on another machine. It's untested, but I have verified

    that it
    > passes "perl -T -c".
    >
    > --
    > Rocco Caputo - http://poe.perl.org/
    >
    > #!/usr/bin/perl -Tw
    >
    > use warnings;
    > use strict;
    >
    > use Socket;
    > use POSIX qw(errno_h);
    >
    > # Import POE and the extra modules we'll need within it.
    >
    > use POE qw( Wheel::ReadWrite Wheel::SocketFactory Filter::Stream );
    >
    > # Some aspects of redirection.
    >
    > use constant LOCAL_ADDRESS => "1.6.20.15";
    > use constant LOCAL_PORT => 6666;
    > use constant REMOTE_ADDRESS => "12.1.2.135";
    >
    > my @open_redirects = (9600..9619);
    >
    > # Create a session that will forward data between two sockets.
    >
    > sub forwarder_create {
    > my ($handle, $port) = @_;
    >
    > POE::Session->create(
    > inline_states => {
    > _start => \&forwarder_start,
    > _stop => \&forwarder_stop,
    > client_input => \&forwarder_client_input,
    > error => \&forwarder_error,
    > server_connect => \&forwarder_server_connect,
    > server_input => \&forwarder_server_input,
    > },
    > args => [ $handle, $port ]
    > );
    > }
    >
    > # The forwarder is actually starting. Begin interacting with the
    > # client, and begin connecting to the server.
    >
    > sub forwarder_start {
    > my ($heap, $socket, $remote_port) = @_[HEAP, ARG0, ARG1];
    >
    > $heap->{state} = 'connecting';
    > $heap->{queue} = [];
    > $heap->{port} = $remote_port;
    >
    > $heap->{wheel_client} = POE::Wheel::ReadWrite->new(
    > Handle => $socket,
    > Filter => POE::Filter::Stream->new,
    > InputEvent => 'client_input',
    > ErrorEvent => 'error',
    > );
    >
    > $heap->{wheel_server} = POE::Wheel::SocketFactory->new(
    > RemoteAddress => REMOTE_ADDRESS,
    > RemotePort => $remote_port,
    > SuccessEvent => 'server_connect',
    > FailureEvent => 'error',
    > );
    > }
    >
    > # The forwarder has stopped. Put its port at the end of the open
    > # redirects list so it can be reused.
    >
    > sub forwarder_stop {
    > push @open_redirects, $_[HEAP]->{port};
    > }
    >
    > # The forwarder has received data from its client side. Queue the
    > # data if the server connection hasn't been established yet.
    > # Otherwise send it through to the server.
    >
    > sub forwarder_client_input {
    > my ( $heap, $input ) = @_[ HEAP, ARG0 ];
    >
    > if ( $heap->{state} eq 'connecting' ) {
    > push @{ $heap->{queue} }, $input;
    > return;
    > }
    >
    > return unless exists $heap->{wheel_server};
    > $heap->{wheel_server}->put($input);
    > }
    >
    > # A server connection was successfully made. Send any pending data to
    > # it.
    >
    > sub forwarder_server_connect {
    > my ( $kernel, $session, $heap, $socket ) = @_[ KERNEL, SESSION, HEAP,

    ARG0 ];
    >
    > # Replace the SocketFactory wheel with a ReadWrite wheel, so we can
    > # interact with the server.
    >
    > $heap->{wheel_server} = POE::Wheel::ReadWrite->new(
    > Handle => $socket,
    > Filter => POE::Filter::Stream->new,
    > InputEvent => 'server_input',
    > ErrorEvent => 'server_error',
    > );
    >
    > # Send pending data to the server.
    > if (@{$heap->{queue}}) {
    > $heap->{wheel_server}->put( @{$heap->{queue}} );
    > $heap->{queue} = [];
    > }
    > }
    >
    > # The forwarder has received data from its server side. Pass that
    > # through to the client.
    >
    > sub forwarder_server_input {
    > my ( $heap, $input ) = @_[ HEAP, ARG0 ];
    > return unless exists $heap->{wheel_client};
    > $heap->{wheel_client}->put($input);
    > }
    >
    > # The forwarder has received an error from either the client or
    > # server. Shut it all down.
    >
    > sub forwarder_error {
    > my $heap = $_[HEAP];
    > delete $heap->{wheel_client};
    > delete $heap->{wheel_server};
    > }
    >
    > ###--------------------------------------------------------------
    > ### This is the listening part of the redirector.
    >
    > # Create a session that acts as the forwarder server.
    >
    > sub server_create {
    > POE::Session->new(
    > _start => \&server_start,
    > _child => \&forwarder_status,
    > accept_success => \&server_accept_success,
    > accept_failure => \&server_accept_failure,
    > );
    > }
    >
    > # Start the server.
    >
    > sub server_start {
    > my $heap = $_[HEAP];
    >
    > $heap->{server_wheel} = POE::Wheel::SocketFactory->new(
    > BindAddress => LOCAL_ADDRESS,
    > BindPort => LOCAL_PORT,
    > Reuse => 'yes',
    > SuccessEvent => 'accept_success',
    > FailureEvent => 'accept_failure',
    > );
    > }
    >
    > # The status of a forwarder has changed. If a forwarder is going
    > # away, it means we have one more redirect port open. Check to see if
    > # the server should resume accepting connections.
    >
    > sub forwarder_status {
    > my $op = $_[ARG0];
    > return unless $op eq "lose";
    > $_[HEAP]->resume_accept() if @open_redirects == 1;
    > }
    >
    > # The server has accepted a client connection. Start forwarding.
    >
    > sub server_accept_success {
    > my ( $heap, $socket, $peer_addr, $peer_port ) = @_[ HEAP, ARG0, ARG1,

    ARG2 ];
    >
    > # Grab the next open redirect port in our list.
    > my $next_remote_port = shift @open_redirects;
    > forwarder_create($socket, $next_remote_port);
    >
    > # Temporarily stop accepting connections if there are no more
    > # redirect ports.
    > $heap->{server_wheel}->pause_accept() unless @open_redirects;
    > }
    >
    > # The server encountered an error. Shut it down if we've run out of
    > # file descriptiors. A serious port redirector would handle this more
    > # gracefully.
    >
    > sub server_accept_failure {
    > my ( $heap, $operation, $errnum, $errstr ) = @_[ HEAP, ARG0, ARG1,

    ARG2 ];
    > delete $heap->{server_wheel} if $errnum == ENFILE or $errnum == EMFILE;
    > }
    >
    > # Main loop. Create a single listening socket that redirects
    > # connections to one of a pool of remote sockets.
    >
    > server_create();
    > POE::Kernel->run;
    > exit;
    >
     
    news.hinet.net, Sep 20, 2004
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fmp Fmpf
    Replies:
    0
    Views:
    84
    Fmp Fmpf
    May 27, 2008
  2. Krisztian VASAS

    problem between perl-gtk2 and POE::Session

    Krisztian VASAS, Jun 21, 2004, in forum: Perl Misc
    Replies:
    1
    Views:
    101
    Rocco Caputo
    Jun 24, 2004
  3. Krisztian VASAS

    Problem with Gtk2 and POE

    Krisztian VASAS, Jun 28, 2004, in forum: Perl Misc
    Replies:
    4
    Views:
    122
    Rocco Caputo
    Jun 30, 2004
  4. Kurt M. Weber

    POE::Component::IRC::State and nick changes

    Kurt M. Weber, Nov 9, 2007, in forum: Perl Misc
    Replies:
    0
    Views:
    91
    Kurt M. Weber
    Nov 9, 2007
  5. Mpapec

    POE and SOAP

    Mpapec, Mar 14, 2008, in forum: Perl Misc
    Replies:
    0
    Views:
    129
    Mpapec
    Mar 14, 2008
Loading...

Share This Page