user3066571
user3066571

Reputation: 1471

Perl socket connection hangs on external host

I have the below program that makes a socket connection and just reads back the first line the server returns. It works on anything inside my network, but if I try to go outside, it just hangs and doesn't do anything. i.e. smtp.gmail.com on port 25. Not sure what's wrong with it, google searches are not giving me much.

use Socket;
use Net::Ping;

$remote = $ARGV[0];
$port = $ARGV[1];

my $p = Net::Ping->new();
if (!$p->ping($remote)) {
    print STDERR "Error: Invalid hostname\n";
    exit(1);
}

if ($port =~ /\D/) {
    $port = getservbyname($port, 'tcp')
}
if ($port > 65535 || $port < 0) {
    print STDERR "Error: Invalid port\n";
    exit(1);
}
$iaddr = inet_aton($remote);
$paddr = sockaddr_in($port, $iaddr);
$proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto);
connect(SOCK, $paddr);
$line = <SOCK>;
print STDOUT "$line\n";
close(SOCK);

exit(0);

Any help would be appreciated.

Upvotes: 2

Views: 361

Answers (1)

Steffen Ullrich
Steffen Ullrich

Reputation: 123320

There is nothing really wrong with your code, you simply have wrong assumptions.

Your assumption is that Net::Ping can be used to find out if a host is valid, but this assumption is wrong. Net::Ping by default just tries to send an ICMP echo request to the host and expects an ICMP echo response back. But many hosts (like smtp.gmail.com) will not reply to such requests even though the host might be reachable by other means, such as connecting via TCP to a specific port like you do next.

I simply recommend to remove this use of Net::Ping. If the host cannot be connected to then the connect will fail, which should be sufficient. But even if connect succeeds it might happen that your code hangs, since you rely on the server to send some data first. In protocols like SMTP (port 25) or FTP (port 21) the server will send some greeting first, but in other protocols like HTTP (port 80) the client is expected to send data before the server replies. In these cases your code will hang since it does not send any data, and so the server just hangs waiting for a proper request before sending a response.

Apart from that, I recommend to use IO::Socket::IP instead of plain sockets. It not only makes the code simpler, but also works transparently with IPv6. Your code explicitly uses of inet_aton and so only works with IPv4.

Upvotes: 3

Related Questions