Re: POE and Port Redirection
From: Rocco Caputo (troc_at_pobox.com)
Date: 09/18/04
- Next message: Patrick Scheible: "Re: Xah Lee's Unixism"
- Previous message: Eric Bohlman: "Re: Need more efficient use of the substitution operator"
- In reply to: Theo James: "POE and Port Redirection"
- Next in thread: Theo James: "Re: POE and Port Redirection"
- Reply: Theo James: "Re: POE and Port Redirection"
- Reply: news.hinet.net: "Re: POE and Port Redirection"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Sat, 18 Sep 2004 04:58:26 GMT
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;
- Next message: Patrick Scheible: "Re: Xah Lee's Unixism"
- Previous message: Eric Bohlman: "Re: Need more efficient use of the substitution operator"
- In reply to: Theo James: "POE and Port Redirection"
- Next in thread: Theo James: "Re: POE and Port Redirection"
- Reply: Theo James: "Re: POE and Port Redirection"
- Reply: news.hinet.net: "Re: POE and Port Redirection"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|