# $Header: osresp.pl 18-feb-2005.12:44:01 afontana Exp $
#
# osresp.pl
# 
# Copyright (c) 2001, 2005, Oracle. All rights reserved.  
#
#    NAME
#      osresp.pl 
#
#    DESCRIPTION
#      check to see if host is up. returns mavg time taken to return ping
#      and status of 1 is successful.  otherwise status 0 with " " as
#      the response time.
#      usage: perl osresp.pl [-mode <0,1> ] [-txnname <txnname>] 
#                  [-numpackets <N>]
#      If used in advanced mode (-mode 1), a transaction name MUST be 
#      specified. In this mode the output will contain the transaction name,
#      the beacon name, and the packet drop rate (%). Also in this mode if 
#      the ping fails, instead of returning an error message, the value -1 
#      is returned in the status field.
#
#    NOTES
#
#
#    MODIFIED   (MM/DD/YY)
#    afontana    02/10/05 - fix windows timeout bug 
#    afontana    01/30/05 - fix broken Windows drop rate
#    afontana    01/14/05 - fix for RH 3.0
#    skumar      05/25/04 - MAC OS X changes
#    nsharma     05/24/04 - Fix for AIX 
#    sacgoyal    10/14/04 - for fixing bug # 3845374 
#    asawant     02/13/04 - NT Porting
#    sravindh    05/02/04 - Fix internal error in host ping test
#    asawant     06/27/03 - Removing call to undefined routine 'trace'
#    asawant     04/01/03 - Check input parameters thoroughly
#    asawant     12/06/02 - Fixing misselling
#    asawant     11/26/02 - Fixing security breach
#    xxu         06/25/02 - remove /usr/local/bin/perl
#    asawant     03/17/02 - Adding more columns for advanced mode
#    asawant     03/13/02 - Adding beacon name..
#    asawant     02/22/02 - Adding drop rate %
#    asawant     02/14/02 - Adding IP..
#    asawant     02/09/02 - Adding parameter to allow the script to be used by 
#                           a beacon target.
#    rlal        09/14/01 - Adding Linux.
#    aaitghez    07/02/01 - isType to osType
#    aaitghez    06/29/01 - sol to SOL.
#    aaitghez    06/19/01 - removing debug calls.
#    aaitghez    05/31/01 - target undefined early in script.
#    aaitghez    05/31/01 - adding target name to DEBUG.
#    aaitghez    05/31/01 - getting rid of all os dependence.
#    aaitghez    05/30/01 - removing os dependent code.
#    aaitghez    05/14/01 - perl version of osresp.tcl.
#    aaitghez    05/14/01 - Creation
# 

#use strict;
use Getopt::Long; # set up to accept user input

use IO::Handle;

require "semd_common.pl";
my $outputStr = 'em_result=';
my $target;
#target we are checking on
$target = $ENV{EM_TARGET_NAME};
# this is the maxResponseTime for the ICMPPing
$maxResponseTime = $ENV{EM_REC_MAX_RESPONSE_TIME};
my $numPackets = 5; # The number of packets to send out (default is 5)
my $maxTtl = ""; # The max ttl
my $mode = 0;  # 1 for a more complete output. 0 is default
my %cmdLine = ();

# Parse the input parameters and put them in the cmdLine hash table
GetOptions(\%cmdLine,
           "mode=i",
           "txnname=s",
           "beaconname=s",
           "numpackets=i",
           "maxttl=i");

if((exists $cmdLine{"mode"}) && (exists $cmdLine{"txnname"}) && (exists $cmdLine{"beaconname"})) {
    $mode = $cmdLine{"mode"};
    if($mode) {
        $outputStr .= "$cmdLine{txnname}|$cmdLine{beaconname}|";
    }
}

if(exists $cmdLine{"numpackets"}) {
    $numPackets = $cmdLine{"numpackets"};
}

if(exists $cmdLine{"maxttl"}) {
    $maxTtl = $cmdLine{"maxttl"};
}

if(($osType = get_osType()) == -1) {
    print "em_error=unsupported OS\n";
#    EMD_DEBUG("The OS is unsupported.\n", "$target");
    exit 1;
}

# Make sure this is a target name (security provision)
# For this we check for any space in the string (including new line) and
# then if this is a valid hostname (1.2.3.4 is a valid hostname too)
if(($target =~ m/\s+/o) || (!gethostbyname("$target")))
{
  #EMD_DEBUG("Invalid hostname: $!", "$target");
  print "em_error=Invalid hostname.";
  # This is so that the interactive UI picks up the error message
  print "em_error=ping: unknown host: $target ";
  exit 1;
}

# Validate remaining input parameters
if($numPackets < 1)
{
  print "em_error=Invalid number of packets.";
  # This is so that the interactive UI picks up the error message
  print "em_error=ping: bad packet count: $numPackets ";
  exit 1;
}

if((!($maxTtl eq "")) && ($maxTtl < 1))
{
  print "em_error=Invalid time to live.";
  # This is so that the interactive UI picks up the error message
  print "em_error=ping: bad ttl: $maxTtl ";
  exit 1;
}

my $r;

# Set the ttl string appropriately (i.e. "-t $maxTttl")
if (!($maxTtl eq "")) {
  if($osType eq "WIN") {
    $maxTtl = " -i $maxTtl ";
  } elsif ($osType eq "AIX") {
  $maxTtl = " -T $maxTtl ";
  } else {
    $maxTtl = " -t $maxTtl ";
  }
}

if ($osType eq "SOL") { 
#    EMD_TRACE("Getting OS response for Sun OS.\n");
  $ENV{PATH} = "/usr/bin:/usr/sbin:/usr/local/bin:/local/bin";
  if(!($r = `ping -s $maxTtl $target 64 $numPackets | tail -2`)) { 
	  #EMD_DEBUG("Failed to execute ping: $!", "$target");
	  print "em_error=Failed to ping host";
	  exit 1;
  }
} elsif ($osType eq "WIN") { 
#    EMD_TRACE("Getting OS response for Windows.\n");
  if(!($r = `ping -l 64 $maxTtl -n $numPackets $target`)) { 
	  #EMD_DEBUG("Failed to execute ping: $!", "$target");
	  print "em_error=Failed to ping host";
	  exit 1;
  }
} elsif ($osType eq "LNX") {
#    EMD_TRACE("Getting OS response for Linux OS.\n");
  if(!($r = `/bin/ping $target -s 64 -c $numPackets $maxTtl | tail -2`)) {
    #EMD_DEBUG("Failed to execute ping: $!", "$target");
    print "em_error=Failed to ping host";
    exit 1;
  }
} elsif ($osType eq "OSF1" || $osType eq "MAC OS X") {
#    EMD_TRACE("Getting OS response for $osType.\n");
  $ENV{PATH} = "/usr/bin:/usr/sbin:/sbin";
  # There is no maxTtl option on Tru64 and MAC OS X
  if(!($r = `ping -c $numPackets -s 64 $target | tail -2`)) {
	  # EMD_DEBUG("Failed to execute ping: $!", "$target");
	  print "em_error=Failed to ping host";
	  exit 1;
  }
} else {			 
#    EMD_TRACE("Getting OS response for HP OS.\n");
  $ENV{PATH} = "/usr/bin:/usr/sbin";
  if(!($r = `ping $maxTtl $target 64 $numPackets | tail -2`)) {
	  # EMD_DEBUG("Failed to execute ping: $!", "$target");
	  print "em_error=Failed to ping host";
	  exit 1;
  }
}				 

my @resLns = split(m/\n/o, $r);

if ($osType eq "WIN") { 
  # make sure we got three lines back
  if(@resLns < 6) {
      print "em_error=Failed spliting lines from result set";
      exit 1;
  }

  my @origResLns = @resLns;
  splice(@resLns, 0, @resLns - 3);
  
  my @res = split(m/=/o, $resLns[2]);
  
  my $avg = 0;
  if(scalar(@res) != 4) {
      print "em_error=Failed spliting result line from result set";
      exit 1;
  } else {
      # get the average response time
      ($avg) = $res[3] =~ m/\s*(\d+)ms\s*/o;
  }	 
  
  my $dropRate;
  # parse the package drop rate from line 3 of output
  unless(($dropRate) = $resLns[0] =~ m/.*,\s.*,\s.*\s\(([\d\.]+)\%\s.*/o)
  {
     # In the event of 100% drop rate, two lines are ommitted from the 
     # bottom of the output.
     unless(($dropRate) = $resLns[2] =~ m/.*,\s.*,\s.*\s\(([\d\.]+)\%\s.*/o)
  {
      print "em_error=Failed parsing package drop rate";
      exit 1;
  }
     $dropRate = 100;
  }
  # A Note is in order here. Win and UNIX behave differently in regards to the 
  # packet drop rate. On Windows, if a packet is answered (TTL expired, etc.)
  # then it is not considered dropped (although the answering node is not the
  # target node). This is not the case on UNIX. To keep our users isolated
  # from this, we compute our own drop rate based on each packets answer. We
  # are (obviously) exposing the UNIX behavior (which seems correct).
  my $stat = 0;
  my $success = 0;
  if($dropRate != 100) {
    # Ensure that we did not receive a bunch of TTL expired messages (still 
    # shown with 0% packet loss!)
    for($i = 3; (($i < 3 + $numPackets) && ($i < @origResLns)); $i++)
    {
      if($origResLns[$i] =~ m/.*Reply\s+from.*bytes.*time.*/o)
      {
        $stat = 1; # Found at least one postive answer!
        $success++;
      }
    }
  }
  if($stat == 0)
  {
    $avg = '';
    $dropRate = '100.00';
  }
  else # Calculate drop rate!
  {
    $dropRate = sprintf("%.2f", (100 * ($numPackets - $success) / $numPackets));
  }
  if($mode) {
      # add the extra output columns if we are in advanced mode
      $outputStr .= "$avg|$stat|$dropRate||";
  } else {
      $outputStr .= "$avg|$stat";
  }
 
} else {
  my @res;
  if(@resLns > 1) {
    @res = split(m/=/o, $resLns[1]);
  } elsif (@resLns == 1) {
    @res = split(m/=/o, $resLns[0]);
  } else {
      print "em_error=Failed spliting lines from result set";
      exit 1;
  }
  
  if(scalar(@res) == 1) {
      $outputStr .= "|0";
  } else {
      my @resr = split(m/\//, $res[1]);
      # get the average response time
  if(!$maxResponseTime or $maxResponseTime eq "") {
      $outputStr .=  "$resr[1]"."|1";
     
  }
  #Checks whether the parameter is a number or not     
  elsif(!($maxResponseTime=~ /^\d+$/ || $maxResponseTime =~ /^\d+\.\d*$/)){      
      print "em_error=Incorrect max response time parameter = $maxResponseTime\n";       
      exit 1;
  }
  elsif(@resr[1] < $maxResponseTime) {
      $outputStr .=  "$resr[1]"."|1";
  }  
  # If the response time is greater than parameterized max response time , then return warning.
  else {
      print "REC_AVG_RESP_TIME_EXCEEDED=Average Response time is greater than recommended $maxResponseTime milliseconds.\n" ;
      exit 1;
  }
  }      

  
  # add the extra output columns if we are in advanced mode
  if($mode) {
      my $dropRate;
      # parse the package drop rate from line 0 of output
      unless(($dropRate) = ($resLns[0] =~ m/.*,\s.*,\s([\d\.]+)\%\s.*/o))
      {
          # if the packet loss is 100% the line we need to parse is line 1
          unless(($dropRate) = ($resLns[1] =~ m/.*\s([\d\.]+)\%\s.*/o))
          {
              print "em_error=Failed parsing package drop rate";
              exit 1;
          }
      }
      $outputStr .= "|$dropRate||";
  }
}

print "$outputStr\n";

exit 0;

