#!/usr/local/bin/perl
# 
# $Header: ftp_response.pl 01-jul-2005.15:43:59 afontana Exp $
#
# ftp_response.pl
# 
# Copyright (c) 2004, 2005, Oracle. All rights reserved.  
#
#    NAME
#      ftp_response.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    afontana    07/01/05 - fix retries for read timeout 
#    afontana    06/29/05 - catch timeouts better
#    afontana    04/08/05 - fix parse error 
#    afontana    04/06/05 - don't delete file in read-only mode 
#    afontana    01/03/05 - fix symbol ref while strict refs 
#    afontana    12/27/04 - change tries to retries 
#    afontana    11/12/04 - fix retries 
#    afontana    11/08/04 - use strict 
#    afontana    11/02/04 - afontana_service_beacon_ftp
#    afontana    11/02/04 - add sleep 
#    afontana    11/01/04 - Creation
#

##
## Note that this requires a special modified version of Net::DNS
## in order to get timing data accurately.
##
use Net::FTP;
use Net::FTP::dataconn;
use Time::HiRes qw(gettimeofday tv_interval);
use ParseStdin;
use strict;

ParseStdin::initStdin();

my $txnname = ParseStdin::getParameter("TxnName");
my $beaconname = ParseStdin::getParameter("BeaconName");
my $host = ParseStdin::getParameter("host", "127.0.0.1");
my $port = ParseStdin::getParameter("port", 21);
my $filename = ParseStdin::getParameter("filename", "");
my $readwrite = ParseStdin::getParameter("readwrite", "readwrite");
my $username = ParseStdin::getParameter("username", "anonymous");
my $password = ParseStdin::getParameter("password", $txnname ."@" . $beaconname);
my $timeout = ParseStdin::getParameter("timeout", 120);
my $numretries = ParseStdin::getParameter("numretries", 2);
my $retryInterval = ParseStdin::getParameter("retryInterval", 120);
my $numbytes = ParseStdin::getParameter("numbytes", 1000);

my $actualtries = 0;
my $success = 0;

my $connect_time = "";
my $login_time = "";
my $noop_time = "";
my $write_time = "";
my $write_rate = "";
my $read_time = "";
my $read_rate = "";
my $total_time = "";
my $error = "";
my $numbytes_read = 0;
my $ftp = 0;

my $t0;
my $t1;

while ($actualtries < ($numretries + 1) && $success == 0) {

  sleep($retryInterval) unless $actualtries == 0;

  $actualtries += 1;
  $success = 0;
  $connect_time = "";
  $login_time = "";
  $noop_time = "";
  $write_time = "";
  $read_time = "";
  $total_time = "";
  $error = "";

  #Connect
  $error = "Connect Error";
  $t0 = [gettimeofday];
  $ftp = Net::FTP->new($host,
		       Port => $port,
		       Timeout => $timeout,
		       Debug => 1);
  next unless ($ftp);
  $t1 = [gettimeofday];
  $connect_time = tv_interval($t0, $t1);
  if ($connect_time > $timeout){
    $error = "Connect Timeout";
    next;
  }


  #Login
  $error = "Login Error";
  $t0 = [gettimeofday];
  eval{next unless $ftp->login($username, $password);};
  $t1 = [gettimeofday];
  $login_time = tv_interval($t0, $t1);
  if ($login_time > $timeout){
    $error = "Login Timeout";
    next;
  }
  next if ($@);


  #NOOP
  $error = "NOOP Error";
  $t0 = [gettimeofday];
  eval{next unless ($ftp->command("NOOP")->response == $ftp->CMD_OK);};
  $t1 = [gettimeofday];
  $noop_time = tv_interval($t0, $t1);
  if ($noop_time > $timeout){
    $error = "NOOP Timeout";
    next;
  }
  next if ($@);


  #Write

  my $buffer0_len = $numbytes % 1000;
  my $buffer0;
  my $checksum = 0;
  my $buffer1;

  if (lc($readwrite) =~ /write/) {
    if ($buffer0_len > 0) {
      $buffer0 = genString($buffer0_len);
      $checksum = genSum($buffer0, 0);
    }

    if ($numbytes >= 1000) {
      $buffer1 = genString(1000);
      for (my $i = $buffer0_len; $i<$numbytes; $i +=1000) {
	$checksum = genSum($buffer1, $checksum);
      }
    }

    #Delete previous, don't care if it gets an error or not
    eval{$ftp->delete($filename);};

    $error = "Write Error";
    $t0 = [gettimeofday];
    my $response;
    eval{$response = $ftp->stor($filename);};
    next unless ($response);
    if ($@) {
      $t1 = [gettimeofday];
      $write_time = tv_interval($t0, $t1);
      $error = "Write Timeout" if ($write_time > $timeout);
      next;
    }


    if ($buffer0_len > 0) {
      eval{$response->write($buffer0, $buffer0_len, $timeout);};
      if ($@) {
	$t1 = [gettimeofday];
	$write_time = tv_interval($t0, $t1);
	$error = "Write Timeout" if ($write_time > $timeout);
	next;	
      }
    }

    if ($numbytes >= 1000) {
      for (my $i = $buffer0_len; $i<$numbytes; $i +=1000) {
	eval{$response->write($buffer1, 1000, $timeout);};
	if ($@) {
	  $t1 = [gettimeofday];
	  $write_time = tv_interval($t0, $t1);
	  $error = "Write Timeout" if ($write_time > $timeout);
	  next;
	}
      }
    }
    eval{next unless ($response->close());};
    next if ($@);
    $t1 = [gettimeofday];
    $write_time = tv_interval($t0, $t1);
    if ($write_time > $timeout) {
      $error = "Write Timeout";
      next;
    }
  }

  #Read
  $error = "Read Error";
  if (lc($readwrite) =~ /read/) {

    my $read_checksum = 0;

    $t0 = [gettimeofday];
    my $response;
    eval{$response = $ftp->retr($filename);};
    next unless ($response);
    if ($@) {
      $t1 = [gettimeofday];
      $read_time = tv_interval($t0, $t1);
      $error = "Read Timeout" if ($read_time > $timeout);
      next;
    }

    my $numbytes_buffer = 0;
    eval{do {
      $numbytes_buffer = $response->read($buffer0, 1000, $timeout);
      $read_checksum = genSum($buffer0, $read_checksum);
      $numbytes_read += $numbytes_buffer;
    } while ($numbytes_buffer);};
    if ($@) {
      $t1 = [gettimeofday];
      $read_time = tv_interval($t0, $t1);
      $error = "Read Timeout" if ($read_time > $timeout);
      next;
    }
    eval{next unless ($response->close());};
    next if ($@);
    $t1 = [gettimeofday];
    $read_time = tv_interval($t0, $t1);

    if (lc($readwrite) =~ /write/) {

      if ($numbytes_read != $numbytes) {
	$error = ("Wrote " . $numbytes . " bytes.  Read "
		  . $numbytes_read . "bytes.");
	next;
      }

      if ($read_checksum != $checksum) {
	$error = ("Checksum Mismatch " . $read_checksum . " vs. " . $checksum);
	next;
      }
    }
    if ($read_time > $timeout) {
      $error = "Read Timeout";
      next;
    }

  }

  if (lc($readwrite) =~ /write/) {
    $error = "Delete Error";
    eval{$ftp->delete($filename);};
    next if ($@);
  }

  $total_time = $connect_time + $login_time + $noop_time + $write_time + $read_time;
  if ($total_time > $timeout) {
    $error = "Transaction Timeout";
    next;
  }

  $error = "";
  $success = 1;
}

#Cleanup
if ($ftp) {
  eval{$ftp->quit();};
  if ($success && $@){
    $error = "Close Error";
    $success = 0;
  } 
}

# Convert seconds to millis
$connect_time *= 1000;
$login_time *= 1000;
$noop_time *= 1000;
$write_time *= 1000;
$read_time *= 1000;
$total_time *= 1000;

if ($write_time && $numbytes) {
  $write_rate = ($numbytes / $write_time);
}

if ($read_time && $numbytes_read) {
  $read_rate = ($numbytes_read / $read_time);
}


if ($success) {
  print "em_result=";
  print ($txnname ."|");
  print ($beaconname . "|");
  print ($success . "|");
  print ($total_time . "|");
  print ($connect_time . "|");
  print ($login_time . "|");
  print ($noop_time . "|");
  print ($write_time . "|");
  printf "%.2f|", $write_rate;
  print ($read_time . "|");
  printf "%.2f|", $read_rate;
  print (($actualtries - 1) ."|");
  print $error;
} else {
  print "em_result=";
  print ($txnname ."|");
  print ($beaconname . "|");
  print ("0|");
  print "|";
  print "|";
  print "|";
  print "|";
  print "|";
  print "|";
  print "|";
  print "|";
  print (($actualtries - 1) ."|");
  print $error;
}

sub genString
{
  my $genString_size = shift;
  my @genString_string = qw(a b c d e f g h i j k l m n o p q r s t  u v w x y z);

  my $genString_result = "";

  while ($genString_size--) {
    $genString_result .= @genString_string[$genString_size % 26];
  }
  return $genString_result;
}

sub genSum
{
  my @genSum_string = unpack("C*", shift);
  my $genSum_sum = shift;
  foreach my $genSum_var (@genSum_string) {
    $genSum_sum += $genSum_var;
  }
  return $genSum_sum % 4096;
}

1;

#print $ftp;
