#!/usr/bin/perl -w

use lib "/etc/qos/scripts/userap_files";

use UserapCommon;
use UserapParser;

$PACKETSIZE = 1200;
$PACKETCOUNT = 20;
$PACKETDELAY= 30;
$PARALLEL = 4;
$UPERIOD = 60;

my $DATAOUT_ENABLED = 1;
my $HTMLOUT_ENABLED = 1;
#generuje system web
my $WWWFILE = "/var/www/system.html";
my $DHEADFILE = "/var/tmp/pihead.tml";
my $HEADFILE = "$QOSBIN/scripts/userap_files/html_templates/system_head";
my $TAILFILE = "$QOSBIN/scripts/userap_files/html_templates/system_tail";


sub plcol {
    my ($tpl) = @_;
    my $color = "black";
    my $prob = 0;
    if ($tpl < 5) {
        $color = "green";
    } elsif ($tpl <15) {
        $color = "orange";
	$prob = 1;
    } elsif ($tpl < 100) {
        $color = "red";
	$prob = 2;
    } elsif ($tpl == 100) {
        $color = "grey";
    }
    $color = "<font color=\"$color\">$tpl</font>";
    return ($color,$prob);
}

sub mincol {
    my ($tpl) = @_;
    my $color = "black";
    my $prob = 0;
    if ($tpl eq "U") {
        $color = "grey";
    } elsif ($tpl < 10) {
        $color = "green";
    } elsif ($tpl <20) {
        $color = "orange";
	$prob = 1;
    } else {
        $color = "red";
	$prob = 2;
    }
    $color = "<font color=\"$color\">$tpl</font>";
    return ($color,$prob);
}

sub avgcol {
    my ($tpl) = @_;
    my $color = "black";
    my $prob = 0;
    if ($tpl eq "U") {
        $color = "grey";
    } elsif ($tpl < 50) {
        $color = "green";
    } elsif ($tpl <100) {
        $color = "orange";
	$prob = 1;
    } else {
        $color = "red";
	$prob = 2;
    }
    $color = "<font color=\"$color\">$tpl</font>";
    return ($color,$prob);
}

sub maxcol {
    my ($tpl) = @_;
    my $color = "black";
    my $prob = 0;
    if ($tpl eq "U") {
        $color = "grey";
    } elsif ($tpl < 100) {
        $color = "green";
    } elsif ($tpl <200) {
        $color = "orange";
	$prob = 1;
    } else {
        $color = "red";
	$prob = 2;
    }
    $color = "<font color=\"$color\">$tpl</font>";
    return ($color,$prob);
}



sub check_targets {
    my ($IPS,$face) = @_;

    my $res = {};
    my $alive= {};
    my $reachable= {};
    my $ping= {};
    my $ipspace ="";
    $res->{alive} = $alive;
    $res->{reachable} = $reachable;
    $res->{ping} = $ping;

    #get list of all ips on interface
    while (my ($id,$ipl) = each %{$IPS}) {
	if ($id == 0) { next;};
	print "$id $ipl\n" if $verbosemode;
	my @ipa = split (":",$ipl);
	$ipspace = $ipspace." ".join (" ",@ipa);
    }
    
    #ping'em all
    print "$$: probing ...\n" unless $quietmode;
    my @response = `fping -a -C2 -p 100 $ipspace 2>&1`;
    foreach (@response) {
        my ($ip,$line) = split(":",$_);
	if ($line) {
    	    #print "R: $_\n";
    	    chomp ($line);
    	    if ($line =~ /- -/) {
		print "  $ip not responding ($line)\n" if $verbosemode;
		$ip =~ s/ //g;
		$alive->{$ip}="0";
	    } else {
		print "  $ip alive ($line)\n" if $verbosemode;
		$ip =~ s/ //g;
		$alive->{$ip}="1";
	    }
	}
    }
    
    $ipspace ="";
    #sleep to stablize arp reachability
    print "$$: waiting for arp change ...\n" unless $quietmode;
    sleep 3;
    #get hash of all reachable IP from arp
    my @ipn = `ip n show dev $face`;
    foreach (@ipn) {
	my $line = $_;
	if ($line =~ /FAILED/ ) {
	    my ($ip) = split(" ",$line);
	    $reachable->{"$ip"} = 0;
	    #print "$ip not reachable \n";
	} else {
	    my ($ip) = split(" ",$line);
	    $reachable->{"$ip"} =1 ;
	    #print "$ip reachable\n";
	}
    }
    
    #create hash of pingable IP's
    while (my ($id,$ipl) = each %{$IPS}) {
	if ($id == 0) { next;};
	#print "$id $ipl\n";
	my @ipa = split (":",$ipl);
	foreach (@ipa ) {
	    my $ip = $_;
	    if ($alive->{"$ip"}) {
		#got alive IP
		$ping->{$id}=$ip;
		if ($ipspace eq "") {
		    $ipspace = $ip;
		} else {
		    $ipspace = $ipspace ." $ip";
		}
		last;
	    } else {
		#check if IP is reachable by arp
		if ($reachable->{$ip}) {
		    $ping->{$id}= "!$ip";
		}
	    }
	}
    }
    $res->{ipspace} = $ipspace;    
    return $res;
}


sub perform_ping {
    my ($fcc) = @_;
    my $alive = $fcc->{alive};
    my $ipspace = $fcc->{ipspace};
    
    my $results = { };

    my %HOSTS = ();
    my %dupici = ();

    my $command ="fping -b $PACKETSIZE -c $PACKETCOUNT -p $PACKETDELAY -i $PACKETDELAY -q $ipspace 2>\&1";
    print "$$: executing ping (size:$PACKETSIZE count:$PACKETCOUNT delay:$PACKETDELAY)\n" unless $quietmode;
    print "$$: targets $ipspace\n" if $verbosemode;

    open FILE, "$command |";

    while (<FILE>) {
        chomp;$line=$_;
        if ($line =~ /duplicate/ ) {
    	    my ($host) = split(":", $line);
	    $host =~s/ //g; chomp $host;
	    if (exists($dupici{"$host"})) {
		$dupici{"$host"} = $dupici {"$host"}+1;
	    } else { $dupici{"$host"} = 1; }
	} elsif ($line =~ /xmt/ ) {
	    my ($host) = split(":", $line);
	    $host =~s/ //g; chomp $host;
	    my (undef, $val1, $val2) = split("=", $line);
	    (undef, $val1) = split("/", $val1);
	    my ($val3, $val4, $val5) = ("U", "U", "U");
	    if (defined ($val2)) {
	        ($val3, $val4, $val5)= split ("/", $val2);
	    }
	    $val3 =~ s/ //g;
	    my $val6 = 0;
	    if (exists($dupici{"$host"})) {
		$val6 = $dupici{"$host"}
	    }
	    #print "$host:$val1, $val3, $val4, $val5, $val6 \n";
	    my $pl = $PACKETCOUNT - ($val1-$val6);
	    $pl = $pl / ($PACKETCOUNT / 100);
	    $results->{"$host"}=join("::",$pl,$val6,$val3,$val4,$val5);
	    print "$host : PL:$pl DUP:$val6 MIN:$val3 AVG:$val4 MAX:$val5)\n" if $verbosemode;

	}
    }
    close FILE;
    print ("$$: done\n") unless $quietmode;
    return $results;

}

sub get_traffic {
    if (open IF, "$TRAFFICDIR/tc_dump.xml") {
	if ($verbosemode) {print "loading data from shaper ($TRAFFICDIR/counter.xml)";}
	my $cnt =0;
	while (<IF>) {
	    $line = $_;
	    if ($line =~ /interfacesumdata/ ) {
		while (<IF>) {
		    $line = $_;
		    if ($line =~ /\/interfacesumdata/ ) {
			last;
		    } 
		    if ($line =~ /user id/ ) {
			my (undef,$uid,undef,$dev,$rest) = split ("'", $line);
			if ($uid == 0) {
			    next;
			}
			my ($sval) = split("<", $rest);
			my (undef,$send) = split(">",$sval);
			$cnt++;
			#$tdatas{"$uid:$dev"}=$send;
			#print "data:$uid:$dev:$send\n";
		    }
		}
	    }
	}
	if ($verbosemode) {print " $cnt entries.\n";}
	close IF;
    } else {
	print "W: cannot open traffic stat file!\n";
    }
}

sub gen_stats {
    my ($IPS,$face,$fcc,$d_pings) = @_;
    my $alive = $fcc->{alive};
    my $ipspace = $fcc->{ipspace};
    my $ping = $fcc->{ping};
    my $probs = {};

    my $WTMPFILE = "/var/tmp/$$.wtmp";
    my $TMPFILE = "/var/tmp/$$.ptmp";
    `touch $TMPFILE` if $DATAOUT_ENABLED;
    open OF,">$TMPFILE" if $DATAOUT_ENABLED; 
    open WF,">$WTMPFILE" if $HTMLOUT_ENABLED;
    open PF, ">/var/state/qos/ppenalt-$face";

    if ($HTMLOUT_ENABLED) {
	print WF "<h4>$face</h4>\n";
        print WF "<table>\n";
        print WF "<tr><th colspan=3>info</th><th colspan=5>posledni test</th><th>stav</th></tr>";
        print WF "<tr><th>id</th><th>nick</th><th>IP</th><th>PL</th><th>dup</th><th>min</th><th>avg</th><th>max</th><th>&nbsp;</th></tr>\n";
    }
    
    my @pole =();

    while (my($id,undef) = each %{$IPS}) {
        push @pole, $id;
    }
    @pole = sort {$a <=> $b} @pole;
    foreach (@pole) {
	my $id = $_;
	if ($id == 0) { next;}
	
	my $nicks = UserapParser::loadNicks();
	my $problem = 0;
	
	if (exists $ping->{$id}) {
	    if ($ping->{$id} =~ /!/ ) {
		print "$id : reachable but not pingable ($ping->{$id})\n" if $verbosemode;
		#PL DUP PMIN PAVG PMAX
		print OF "ping==$face==$id==$nicks->{$id}==100;U;U;U;U\n" if $DATAOUT_ENABLED;
		my $pperc = $ifi->{$face}->{"nopingpenalty"};
		print PF "$id $pperc AUTO:zadna odezva na ping\n";
		print  "  $id $pperc AUTO:zadna odezva na ping\n" if $verbosemode;
		if ($HTMLOUT_ENABLED) {
		    my $color="red";
	    	    print WF "<tr>";
	    	    print WF "<td>$id</td><td bgcolor=\"$color\" width='120'> $nicks->{$id} </td><td bgcolor=\"$color\" width='120'>$ping->{$id}</td><td><font color='red'>100</font></td><td>--</td><td>--</td><td>--</td><td>--</td>\n";
		    print WF "<td><font color='red' align='center'>nejde ping!</font></td>\n";
	    	    print WF "</tr>\n";
		}
	    } else {
		print "$id : pingable - $ping->{$id} - $d_pings->{$ping->{$id}}\n" if $verbosemode;
		print OF "ping==$face==$id==$nicks->{$id}==$d_pings->{$ping->{$id}}\n" if $DATAOUT_ENABLED;
		if ($HTMLOUT_ENABLED) {
		    my ($pl,$dup,$min,$avg,$max) = split("::",$d_pings->{$ping->{$id}});
		    my ($plc,$pr1) = plcol($pl);
        	    my ($avgc,$pr2) = avgcol ($avg);
		    my ($minc,$pr3) = mincol ($min);
        	    my ($maxc,$pr4) = maxcol ($max);
		    $problem = ($pr1 + $pr2 + $pr3 + $pr4) * 10;
		    $problem = 70 if ($problem > 70);
		    my $stav = "";
		    if ($problem < 10) {
			$stav = "<font color='green'>OK</font>";
		    } elsif ($problem < 30) {
			$stav = "<font color='magenta'>varovani</font>";
		    } else {
			$stav = "<font color='red'>KRIZE</font>";
		    }
		    if ($problem) {
			my $pperc = 100 - $problem;
			print PF "$id $pperc AUTO:spatna odezva\n";
			print  "  $id $pperc AUTO:spatna odezva\n" if $verbosemode;
		    }
		    my $color="lime";
	    	    print WF "<tr>";
	    	    print WF "<td>$id</td><td bgcolor=\"$color\" width='120'> $nicks->{$id} </td><td bgcolor=\"$color\" width='120'>$ping->{$id}</td><td>".$plc."</td><td> $dup</td><td>".$minc." </td><td>".$avgc." </td><td>".$maxc." </td>\n";
		    print WF "<td align='center'>$stav</td>\n";
	    	    print WF "</tr>\n";
		}
	    }
	} else {
	    print "$$ : $id : offline\n" if $verbosemode;
    	    print OF "ping==$face==$id==$nicks->{$id}==U;U;U;U;U\n" if $DATAOUT_ENABLED;
	    if ($HTMLOUT_ENABLED) {
	        my $color="grey";
		print WF "<tr>";
	    	print WF "<td>$id</td><td bgcolor=\"$color\" width='120'> $nicks->{$id} </td><td bgcolor=\"$color\" width='120'>N/A</td><td bgcolor=\"$color\">--</td><td bgcolor=\"$color\">--</td><td bgcolor=\"$color\">--</td><td bgcolor=\"$color\">--</td><td bgcolor=\"$color\">--</td>\n";
		print WF "<td bgcolor='grey' align='center'>offline</font></td>\n";
	    	print WF "</tr>\n";
	    }
	}
    }
    if ($DATAOUT_ENABLED) {
	close OF;
	print "$$: dumping results.. \n" if $verbosemode;
	my $cmd = "mv $TMPFILE $DATADIR/pinger-".$face.".txt";
	`$cmd`;
    };
    if ($HTMLOUT_ENABLED) {
        print WF "</table>\n";
	close WF;
	my $cmd = "mv $WTMPFILE $DATADIR/tpinger-".$face.".twww";
	`$cmd`;
    };
    close PF;
}

# ==========================================================
`mkdir /var/www/state/ 2>/dev/null`; #prasarna no :) 

our $verbosemode = 0;
our $quietmode = 0;

foreach (@ARGV) {
    $quietmode=1 if (($_ eq "-q") || ($_ eq "--quiet"));
    $verbosemode=1 if (($_ eq "-v") || ($_ eq "--verbose"));
    if ($_ eq "--help" || $_ eq "-h") {
	print "usage ./pinger.pl [-v] [-l]\n  -v  activates verbose mode\n  -l  activates loop mode\n";	exit 0;
     }
}

open GWF, ">$DHEADFILE" if $HTMLOUT_ENABLED;
if ($HTMLOUT_ENABLED) {
    #open IF, "$QOSBIN/scripts/userap_files/html_templates/system_head";
    #while (<IF>) { print GWF $_;}
    #close IF;
    print GWF `uptime`."<br>";
    print GWF `cat /proc/net/ip_conntrack | wc -l `."/ ".`cat /proc/sys/net/ipv4/ip_conntrack_max`." spojeni <br>";
    print GWF "<hr>\n";
    print GWF "<h3>Pinger status</h3>\n";
    close GWF;
}

#if ($TRAFFIC_ENABLED) {get_traffic;}

our $ifi = UserapParser::getIfacesInfo();

my $processes = 0;

while (my ($wface,$fdata) = each %{$ifi}) {
    #todo - only if enabled
    next if ($wface =~ /imq/ );
    next unless ($fdata->{ping} == 1);
    if ($fdata->{type} eq "userap") {

	if ($processes >= $PARALLEL) {
	    my $pid = wait;
	    $processes--;
	    if ($processes <0) {$processes =0};	
	}
    
	$processes++;
	my $return=fork;
	if ($return == 0) {
	    print "$$: Starting on $wface ..\n";
	    my $IPS = UserapParser::GetIPs($wface);
	    my $res1 = check_targets($IPS,$wface);
	    gen_stats($IPS,$wface,$res1,perform_ping($res1));
	    exit 0;
	}
    }
}
while ($processes) {
    my $pid = wait;
    last if $pid < 0;
    $processes--;
    if ($processes <0) {$processes =0};
}

if ($DATAOUT_ENABLED) {
    open OF,">/var/www/state/pinger.txt";
    print OF time()."\n";
    close OF;
    `cat $DATADIR/pinger*.txt >>/var/www/state/pinger.txt`;
    `rm -f $DATADIR/pinger*.txt`;
}

if ($HTMLOUT_ENABLED) {
    #open GWF, ">$GWTMPFILE" if $HTMLOUT_ENABLED;
    #while (<IF>) {
    #    print GWF $_;
    #}
    #close GWF;
    
    `cat $HEADFILE $DHEADFILE $DATADIR/*.twww $TAILFILE > $WWWFILE`;
    `cat $DATADIR/ppenalt* > $DATADIR/penalty-auto`;
    `rm -f $DATADIR/ppenalt*`;
    `rm -f $DATADIR/*.twww`;
    #`mv $GWTMPFILE $WWWFILE`;
}

# ==========================================================
