Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Is there any way to connect two sockets together?

by zigster (Hermit)
on Jan 11, 2001 at 19:34 UTC ( [id://51126]=perlquestion: print w/replies, xml ) Need Help??

zigster has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to write a process that essentially acts as an conduit between two other proceses. I want to open a serversocket A and a client socket B. Something like.
$server = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => $local_port, Proto => 'tcp') or die "Cant create server socket: !"; while ($client = $server->accept) { $proxy = IO::Socket::INET->new( PeerAddr => $proxy_host, PeerPort => $proxy_port, Proto => 'tcp') or die "cannot create proxy socket: $!" # At this point here I want to connect the $proxy file handle and # the $client file handle .. }
By connect I mean I want the any op from $client to be shoved into the ip of $proxy and any op from $proxy to be shoved in the ip of $client. Clear .. no not to me either I am sure I am doing summat wrong.

Now I guess I could do this by spawning 2 threads one to read and one to write then just bucket the data across however I am looking for a simpler solution.

I would be keen to hear anyones suggestions. I half think I am missing some thing and should not be even attempting this so please tell me I am being dumb if you see that to be the case.

Thanks very much for your time.
--

Zigster

Replies are listed 'Best First'.
Re: Is there any way to connect two sockets together?
by c-era (Curate) on Jan 11, 2001 at 20:30 UTC
    Here is a simple solution using select (although it will only process one connection at a time). I added comments to the code that I added. You may want to add more error checking.
    use IO::Socket; use IO::Select; $local_port = 5000; $proxy_host = "localhost"; $proxy_port = 6000; $server = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => $local_port, Proto => 'tcp') or die "Cant create server socket: !"; # Create a select object $read = new IO::Select; while ($client = $server->accept) { $proxy = IO::Socket::INET->new( PeerAddr => $proxy_host, PeerPort => $proxy_port, Proto => 'tcp') or die "cannot create proxy socket: $!"; # Unbuffer our output $oldfh = select ($proxy); $| = 1; select ($client); $| = 1; select ($oldfh); # Add our filehandles to our select object $read->add($client); $read->add($proxy); # This will wait until one of the filehandles has something to read while (defined (($readable) = IO::Select->select($read,undef , und +ef, 0))){ foreach $fh (@$readable) { # The client has something to say if ($fh == $client) { $buf = <$client>; if ($buf){ # Lets tell the proxy print $proxy $buf; } else { # The client closed last; } # The proxy has something to say } else { $buf = <$proxy>; if ($buf){ # Lets tell the client print $client $buf; } else { # The proxy closed last; } } } } # Remove our file handles from select and close them $read->remove($client); $read->remove($proxy); $client->close; $proxy->close; } # Now we go onto the next client
    UPDATE: Below is a piece of code that will handle multiple clients, has use strict, and $|=1 taken off.
    use strict; use IO::Socket; use IO::Select; my $local_port = 5000; my $proxy_host = "localhost"; my $proxy_port = 6000; # Used to store client and proxy connections my %client_proxy; my $server = IO::Socket::INET->new( Listen => 5, LocalAddr => 'localhost', LocalPort => $local_port, Proto => 'tcp') or die "Cant create server socket: !"; # Create a select object my $read = new IO::Select; $read->add($server); while (1){ my ($readable) = IO::Select->select($read, undef, undef, 0); foreach my $fh (@$readable){ if ($fh == $server){ # We got a new client, so set up it's configuration my $client = $server->accept; my $proxy = IO::Socket::INET->new( PeerAddr => $proxy_host, PeerPort => $proxy_port, Proto => 'tcp') or die "cannot create proxy socket: $!"; # You probabl +y don't really want to die here. $read->add($client); $read->add($proxy); $client_proxy{$client} = $proxy; $client_proxy{$proxy} = $client; } else { my $buf = <$fh>; if ($buf){ # We need to send some information my $fh2 = $client_proxy{$fh}; print $fh2 $buf; } else { # We need to close our connections my $fh2 = $client_proxy{$fh}; $read->remove($fh2); close ($fh2); delete $client_proxy{$fh2}; $read->remove($fh); close ($fh); delete $client_proxy{$fh}; } } } }
    <SARCASIM>Some people will pick apart the above code because they are jealous that they could write it ; )</SARCASIM>
      Note that IO::Socket file handles are by default set with 'autoflush' enabled, so it's not necessary to do that here, especially not by using the select/$|=1/select method. We are dealing with objects, you know. :) $client->autoflush(1)

      In addition, you might be interested in the 'can_read' method of IO::Select instead of calling select directly. This is a little "friendlier":

      my @readable = $read->can_read; foreach $fh (@readable) { ... }
        I forgot about the autoflush. As for the can_read method, it dosen't work that great on active perl, but the regular select works fine.
(tye)Re: Is there any way to connect two sockets together?
by tye (Sage) on Jan 11, 2001 at 20:09 UTC

    I don't think there is a simpler way (well, unless you consider using select simpler than threads). I wrote such a beast and it works quite nicely for me. There is also one in the Perl Cookbook (if you have a copy or know where to download the code samples -- which I don't, sorry).

    Update: I think this is called a "port mapper" in the Cookbook.

            - tye (but my friends call me "Tye")
      Thanks for the hint, I was playing with select as I read your post ;-) however I was not able to find any references in the cookbook. I had previously looked do you have any idea what section it was it?
      --

      Zigster
        Looks like it's section 17.18, "Program: fwdport".
Re: Is there any way to connect two sockets together?
by zigster (Hermit) on Jan 11, 2001 at 21:30 UTC
    Thanks HUGELY to everyone who has helped me here for the code and the advice. I have all but a working system now.. Thanks guys (and gals).
    --

    Zigster
Re: Is there any way to connect two sockets together?
by jeroenes (Priest) on Jan 11, 2001 at 20:42 UTC
    Why don't you just use SSH for that?
    ssh localhost -f -S -L $localport:$proxy:$proxyport
    and it does exactly what your script is trying to do. But I'm still confused if that is what you want to do, as I see little use for it.

    Cheers,

    Jeroen
    I was dreaming of guitarnotes that would irritate an executive kind of guy (FZ)

    Update: The -S option of SSH makes sure it doesn't try to connect, only functions as portmapper. Moreover, I forgot the supply 'localhost', and the -f option is handy as well.

      Because my script is a cut down of the big picture. In the big picture it tunnels over a http proxy. It opens up a socket connection with a remote internet host via the proxy (using the connect method) this is a trival negotiation1. It then connects the data recieved from that connection to a local port. I can then connect applications to the local port and so to the outside world.

      1 CONNECT host:port HTTP1/0 <NL> or some such.
      --

      Zigster

        Aha.

        Than use the SSH solution I gave you should work. It just tunnels a local connection to $localport to $proxy:$proxyport. You simply let your client connect to $localport and it wouldn't know the difference.

        Hope this helps,

        Jeroen
        I was dreaming of guitarnotes that would irritate an executive kind of guy (FZ)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://51126]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (5)
As of 2024-03-29 10:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found