I was wondering if anyone here has ever written an SMTP test using IO::Socket:INET and/or IO::Select? Basically, I'm trying to connect to my mail server, make sure I got a 220, send a HELO message, and make sure I got a 250 but I'm having trouble reading the response(s) and having the code timeout during a specified time interval if no response is given:
Code:
use IO::Socket::INET;
use IO::Select;
my $addr = 'XX.XX.XX.XX';#mail server ip address
my $hostname = `hostname`;
#set our timeout to 30 sec
my $timeout = 30;
my $endtime = time + $timeout;
my $line;
my $socket;
eval {
# get a connection to the ip
$socket = IO::Socket::INET->new(
PeerAddr => inet_ntoa($addr),
PeerPort => 25,
Timeout => $timeout,
Proto => 'tcp',
);
};
# show message if we couldn't connect
$ipHash{'Message'} = 'Connection refused' unless $socket; # connection refused
# get a select object & add our socket so we can do read timeouts
my $sel = IO::Select->new($socket);
#make sure we got a 220 initially
my $hello;
while ( time < $endtime && ! $@ ) {
unless ($sel->can_read( $endtime-time )) {
# returns time out
$ipHash{'Message'} .= '<br>Connection timed out';
last;
}
my $bytes = $socket->sysread( $line, 4096, length($line) );
if ($line !~ /^220/m && $line) {
$ipHash{'Message'} .= "<br>Connection error: $line";
last;
} else {
$hello = 1;
$ipHash{'Message'} .= "<br>Able to connect successfully";
last;
}
}
#send a HELO if we succesfully connected
if ($hello) {
#reset timeout
my $endtime = time + $timeout;
# return timeout if we timeout waiting to write
$ipHash{'Message'} .= '<br>Connection timed before HELO' unless $sel->can_write( $timeout ); # timeout
# send the hello message
$socket->syswrite("HELO $hostname", length("HELO $hostname"));
# read lines until we get a 250 or time out
# my $line;
my $ableToSend;
while ( time < $endtime && ! $@ ) {
# read a line - should time out when the endtime is here
# unless ($sel->can_read( $endtime-time )) {
# returns time out
# $ipHash{'Message'} .= '<br>HELO response timed out';
# last;
# }
my $bytes = $socket->sysread( $line, 4096, length($line) );
# check the output
if ($line =~ /^250/m) {
# finish the connection, waiting up to 10 seconds
$socket->syswrite("QUIT\n", length("QUIT\n")) if $sel->can_write( 10 );
# return ok
$ipHash{'Message'} .= "<br>Replied to HELO";
$ableToSend = 1;
last;
}
else {
$ipHash{'Message'} .= "<br>HELO error: $line";
last;
}
}
# if we didn't connect
unless($ableToSend) {
$ipHash{'Message'} .= "<br>Did not reply to HELO";
}
}
else {
$ipHash{'Message'} .= "<br>Could not establish connection or response timed out";
}
$socket->close();
I've never written anything like this before so any suggestions on how to make this work or better ways to make this work would be greatly appreciated.