views:

1470

answers:

3

I have a (from what I can tell) perfectly working Linux setup (Ubuntu 8.04) where all tools (nslookup, curl, wget, firefox, etc) are able to resolve addresses. Yet, the following code fails:

$s = new IO::Socket::INET(
    PeerAddr => 'stackoverflow.com',
    PeerPort => 80,
    Proto => 'tcp',
);

die "Error: $!\n" unless $s;

I verified the following things:

  • Perl is able to resolve addresses with gethostbyname (ie the code below works):

    my $ret = gethostbyname('stackoverflow.com'); print inet_ntoa($ret);

  • The original source code works under Windows

  • This is how it supposed to work (ie. it should resolve hostnames), since LWP tries to use this behavior (in fact I stumbled uppon the problem by trying to debug why LWP wasn't working for me)
  • Running the script doesn't emit DNS requests (so it doesn't even try to resolve the name). Verified with Wireshark
A: 

Make sure that you have the statement

use IO::Socket::INET;

At the beginning of your source code. If you leave this out, you are probably getting the error message:

Can't locate object method "new" via package "IO::Socket::INET"

Beyond that you might verify that DNS is working using Net::DNS::Resoler, see more information here.

use Net::DNS;

my $res = Net::DNS::Resolver->new;

# Perform a lookup, using the searchlist if appropriate.
my $answer = $res->search('example.com');
ceretullis
I have the use statement at the beginning of the script. Also, I've tried the second test script, it works (just as to be expected, given that gethostbyname works), but I still have the original problem.
Cd-MaN
+5  A: 

From a quick look, the following code from 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;
}

suggests (if you look at the caller of this code) the work-around of adding MultiHomed => 1, to your code.

Without that work-around, the above code appears to try to call inet_aton("hostname.com") using the inet_aton() from Socket.pm. That works for me in both Win32 and Unix, so I guess that is where the breakage lies for you.

See Socket.xs for the source code of inet_aton:

void
inet_aton(host)
    char *  host
    CODE:
    {
        struct in_addr ip_address;
        struct hostent * phe;

        if (phe = gethostbyname(host)) {
            Copy( phe->h_addr, &ip_address, phe->h_length, char );
        } else {
            ip_address.s_addr = inet_addr(host);
        }

        ST(0) = sv_newmortal();
        if(ip_address.s_addr != INADDR_NONE) {
            sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address );
        }
    }

It appears that the Perl gethostbyname() works better than the C gethostbyname() for you.

tye
Yes! Yes! YES! :-) This was the problem. Thank you so much for the solution.Now all I have to figure out is how to convince LWP to create a special socked (with the multihomed option activated).
Cd-MaN
A: 

Could you perhaps tells us exactly how your code fails? You've got error checking code in there but you haven't reported what the error is!

I've just tried the original code (with the addition of the "use IO::Socket::INET" on my Mac OS X machine and it works fine.

I suspect that the Multihomed option is an unnecessary hack and some other issue is the root cause of your problem.

Alnitak