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

I'm trying to write a package that does a non-blocking multi-homed connect using IO::Socket::INET. As I understand it, IO::Socket::INET cannot connect to a multi-homed host when set to non-blocking mode:

Although it is not illegal, the use of "MultiHomed" on a socket which is in non-blocking mode is of little use. This is because the first connect will never fail with a timeout as the connect call will not block.

The package holds a copy of the socket and a list of the multi-homed IP addresses. If the connection attempt timesout or is refused, I try the next IP in the list.

The problem I'm having is that I can't reuse the socket I created after the first connect call. When I create a new IO::Socket::INET object within the package, I get the error "can't call method "foo" on an unblessed reference".

Is there a way to reuse the IO::Socket::INET object?

Can I associate a new IO::Socket::INET object to the class until all the IP addresses are exausted, or the connection attempt succeeds. How can I do this without unblessing?

Replies are listed 'Best First'.
Re: Multihoming a non-blocking IO::Socket::INET
by polettix (Vicar) on May 25, 2006 at 10:56 UTC
    You misread the documentation. Note that it states that it is not illegal (that means that "it can"), but it's of little use (that means "why would you do such a thing?"). If you set the socket in non-blocking mode, how do you expect to get a timeout?

    Regarding the specific problem, you should probably post a relevant chunk of code.

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
Re: Multihoming a non-blocking IO::Socket::INET
by kwaping (Priest) on May 25, 2006 at 15:14 UTC
Re: Multihoming a non-blocking IO::Socket::INET
by ikegami (Patriarch) on May 29, 2006 at 23:21 UTC

    The addresses for MultiHomed or obtained using the following function in IO::Socket::INET:

    sub _get_addr { my($sock,$addr_str, $multi) = @_; my @addr; if ($multi && $addr_str !~ /^\d+(?:\.\d+){3}$/) { (undef, undef, undef, undef, @addr) = gethostbyname($addr_str); } else { my $h = inet_aton($addr_str); push(@addr, $h) if defined $h; } @addr; }

    To solve your problem, get the addresses in a similar matter, create a non-blocking socket to each address, and wait for one to connect using IO::Select.

    use IO::Select (); use IO::Socket qw( AF_INET SOCK_STREAM ); sub get_addrs { my ($domain) = @_; my (undef, undef, undef, undef, @addr) = gethostbyname($domain); return @addr; } sub aggressive_connect { my ($domain, $port, $timeout) = @_ $timeout ||= 0; my @socks; foreach my $packed_addr (get_addrs($domain)) { my $sock = IO::Socket->new( Domain => AF_INET, # ip (as opposed to unix) Type => SOCK_STREAM, # tcp ); $sock->blocking(0); $sock->connect($port, $packed_addr) or next; push(@socks, $sock); } return (IO::Select->new(@socks)->can_write($timeout))[0]; ) my $sock = aggressive_connect('alistapart.com', 80, 30) or die("Unable to connect\n"); # $sock->blocking(1); # Revert to blocking if so desired.

    Untested.