Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Telnet session disconnect testing

by bajangerry (Sexton)
on Jan 13, 2010 at 14:36 UTC ( #817189=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks,

I have a script monitors a PBX that is streaming call data via specific port and saves this data to a database. The problem I am having is that the script does not notice when the PBX goes offline and will not reconnect when the PBX comes back online(some of these PBXes have programmed reboots in the night). I was wondering what would be the best way for me to add an "alive" type of check to this script to monitor if the PBX is alive and if not to keep testing until it does come alive again at which point it will reconnect to the streaming port. I assume we could use a ping type test for this maybe?

See current code below:

use DBI; use strict; use IO::Socket; use POSIX; # initialize host and port my $host = shift || $ARGV[0]; my $port = shift || $ARGV[1]; my $proto = getprotobyname('tcp'); my $iaddr = inet_aton($host); my $paddr = sockaddr_in($port, $iaddr); for(;;){ my $sock = new IO::Socket::INET(PeerAddr => $host, PeerPort => $port,P +roto => "tcp",) or die "Cannot connect to PBX at address: $host port: $port: $!"; while (<$sock>) { s/^\0+//; # Remove leading null characters print $_; chomp ($_); #$_ =~ s/^[^ ]+//; if ($_ =~m"/") { &TXTout; #send data to the data logging subroutine &DBconnect; #send data to the database subroutine } } #Close While loop sub TXTout { my $dir = "/var/log/smdr/"; # please ensure you create this director +y to get your log files my $filename = strftime("%B%d%Y",localtime(time)); my $fileexpression = $dir.$filename; if (-e $fileexpression){ open(FILE, ">>$fileexpression"); print FILE $_; close (FILE); } else { open FILE, >$fileexpression; print FILE $_; close (FILE); } } sub DBconnect { # MySQL Connection parameters my $dbuser= "root"; my $dbpassword= "Adm1n!"; my $dbhost= "localhost"; my ($line, $mon, $day, $stime, $pm, $hrs, $mins, $sec, $callp, $leaddi +git, $callno, $speed, $callp2, $transf, $acccode, $sysid, $tester); $mon = substr ($_, 1,2); $day = substr ($_, 4,2); $stime = substr($_, 7,5); $pm = substr($_, 12,1); $hrs = substr($_, 14,2); $mins = substr($_, 17,2); $sec = substr($_, 20,2); $callp = substr($_, 23,4); $leaddigit = substr($_, 29,3); $callno = substr($_, 33,26); $speed = substr($_, 60,1); $callp2 = substr($_, 61,5); $transf = substr($_, 67,5); $acccode = substr($_, 72,12); $sysid = substr($_, 85,3); $tester = strftime( "%Y",localtime(time)); if ($acccode == ""){$acccode = 0} # Establish the connection which returns a DB handle my $dbh= DBI->connect("dbi:mysql:database=smdr;host=$dbhost",$dbuser,$ +dbpassword) or die $DBI::errstr; # Prepare the SQL statement my $sth= $dbh->prepare("INSERT INTO import VALUE(?,?,?,?,?,?,?,?,?,?,? +,?,?,?,?,?,?)") or die $DBI::errstr; # Send the statement to the server $sth->execute($mon,$day,$stime,$pm,$hrs,$mins,$sec,$callp,$leaddigit,$ +callno,$speed,$callp2,$transf,$acccode,$sysid,$tester,''); # Close the database connection $dbh->disconnect or die $DBI::errstr; } #Close DBconnect subroutine #close the socket close $sock or die "close: $!"; print "socket closed"; print "<br />"; }

Replies are listed 'Best First'.
Re: Telnet session disconnect testing
by gman (Friar) on Jan 13, 2010 at 15:34 UTC

    Are you sure your not getting any sort of disconnect string? Does the remote server allow more then one session? If so you can setup another process to connect and if it fails, restart your initial connection after some sort of delay.

    I have done some billing feeds like this which where one way communications, and had to restart my connection, if I received no data within a certain time frame. Maybe try using alarm?

      Thanks for the response gman,

      There is not disconnection string that I am aware of. This is one way communication and one of the models of PBX will only allow a single connection to the port.

      I will look into this alarm but still not sure how I would implement it in the same script as the capture processes.
Re: Telnet session disconnect testing
by arkturuz (Curate) on Jan 13, 2010 at 16:10 UTC
    First of all, a little comment on your code: I think there's no need to redefine subroutines inside the for loop all the time. You can move them out of it, unless you have some specific reason not to (on a quick glance, variable scoping ($_) could be an issue). On your problem: you say you have programmed reboots. If they happen at fixed hours, you could try not to connect to the service at that time. Also, instead of die() you could sleep() for some time, and then try reconnecting again.


      Not quite sure I understand your comment regarding the subroutines... I am not that great on Perl but thanks for the input. The problem with your suggestion is that I have provided others with this program to use so to hardcode a reboot time is not really an option here. Will look into the sleep() option though, thanks.
        Not quite sure I understand your comment regarding the subroutines

        Usually, you define your functions once, and rarely put them inside the loops (unless there's some tricky busines going on - like constantly defining new subroutines for some specific tasks). Nevertheless, if it's okay with you, and the program works as expected, then there's no problem. Although it's better for readabilly, maintenance, logic of the program, easier debugging, to do otherwise.

Re: Telnet session disconnect testing
by cdarke (Prior) on Jan 13, 2010 at 16:06 UTC
    You could try setting socket option SO_KEEPALIVE using the sockopt method to IO::Socket. That might give you better notification when it breaks - although I can't say that I have tried it on PBX.


      Thanks for your response but I believe the SO_KEEPALIVE works only if the server you are communicating with responds to a client which is not the case here. The PBX simple streams data as it happens via a port, it does not accept input nor respond to input on that port so I do not think this will work for me but please correct me if I am wrong!
Re: Telnet session disconnect testing
by jklowden (Novice) on Jan 15, 2010 at 05:50 UTC

    I think this is wrong:

    while (<$sock>) {

    Looking at perldoc IO::Socket, you need one or two things:

    • set IO::Socket::timeout to some reasonable value, maybe 1 minute, so you don't wait forever.
    • Test IO::Socket::connected after reading from the socket.

    TCP has a teardown sequence: the sender closes its port; the receiver acknowledges the close and closes its own. . It's very unlikely that rebooting the PBX interferes with that. Your TCP stack knows the sender is gone, but because you're not timing out, you never learn of it.


      Thanks for the response but I am not sure I get your point here. I was assuming that the  while (<$sock>) would provide a means of checking that the link was up and if it is then continue.

      I have checked a few examples of using the IO::Socket::INET and I have not seen anyone using a timeout option so I am not sure how I could implement that, could you explain bit more for me? Maybe an example of it in my code?

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://817189]
Approved by planetscape
Front-paged by planetscape
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2021-07-24 08:40 GMT
Find Nodes?
    Voting Booth?

    No recent polls found