#!/usr/bin/perl -wT

use Net::Ping;
use Time::Piece;
use Time::HiRes;

## Declare functions
sub out;
sub go_sleep;
sub logmsg;
sub error;

$|=1; # autoflush

my $host  = $ARGV[0] or die "Usage: $0 host\n";

my $sleep_start = 1;
my $sleep_more  = 1.25;
my $sleep_max   = 15;
my $mark        = 60 * 60;
my $stat_pings  = 10;

my $sleep = $sleep_start;

logmsg "Started net-uptime ($host)";

my $p = Net::Ping->new('icmp');
# $p->hires( 1 );

#warn scalar $p->ping( $host );


my $state = $p->ping( $host );
my $marked = time;
if( $state )
{
    logmsg "Up   $host";
}
else
{
    logmsg "Down $host";
}

while(1)
{
    go_sleep;

    my $state_new = $p->ping( $host );
    if( $state !=  $state_new )
    {
	$sleep = $sleep_start;

	if( $state_new ) # going up
	{
	    logmsg "Up   $host";
	    $state = $state_new;
	}
	else             # going down
	{
	    # Temporary packet loss?
	    my $cnt = 0;
	    for( my $i=1; $i<$stat_pings; $i++ )
	    {
		sleep 1;
		$cnt ++ if $p->ping( $host );
	    }

	    if( $cnt )
	    {
		logmsg sprintf("%3d%% packet loss",
			       100 * ($stat_pings - $cnt)
			       / $stat_pings );
	    }
	    else
	    {
		logmsg "Down $host";
		$state = $state_new;
	    }
	}
    }
    else
    {
	my $diff = time - $marked;
#	warn "Diff: $diff\n";
	if( $diff > $mark )
	{
	    error "no   change...";
	    $marked = time;
	}
    }
}


sub out
{
    my $t = localtime;
    my $out = "";
    foreach( @_ )
    {
	$out .= sprintf("%s %s: %s\n", $t->ymd, $t->hms("."), $_);
    }
#    warn "logging: $out";
    return $out;
}

sub logmsg
{
    print out( @_ );
}

sub error
{
    print STDERR out( @_ );
}

sub go_sleep
{
#    warn "Sleep for $sleep seconds\n";
    sleep $sleep;
    $sleep = minof( $sleep * $sleep_more, $sleep_max );
}

sub minof
{
    my $min = shift;

    while( defined( my $val = shift ) )
    {
	$min = $val if $val < $min;
    }
    return $min;
}

=pod

This modules reports times then the connection goes up or down and
reports packet loss.

The net is asumed to be down after 10 lost pings. One lost packet is
reported as a 10% packet loss.

Once an houer, a "no change" message is sent to STDERR.

=cut

