#!/usr/bin/perl

use Socket;
#use IO::Handle;
use FileHandle;

$target_rate = $ARGV[0];
if ( $target_rate =='' ){ die "usage: /test.pl <target_rate>\n"; }
chomp( $target_rate );

print "target rate '$target_rate'\n";

### connect to all servers
$sink1 = get_filehandle( '192.84.79.36', 5001 );
$sink2 = get_filehandle( '192.84.79.38', 5001 );
$sink3 = get_filehandle( '192.84.79.39', 5001 );


### connect to all clients
$source1 = get_filehandle( '128.40.89.244', 5003 );
$source2 = get_filehandle( '128.40.89.245', 5003 );
$source3 = get_filehandle( '128.40.89.246', 5003 );


### set up the flow information

#needs password
$iperf{password} = 'gimme';

### initiate servers
$iperf{CMD} = 'START';
$iperf{port} = 5010;
$iperf{report_interval} =  2;
$iperf{type} = 'udp';
$iperf{socketbuffer} = '1m';
$iperf{packet_size} = 1472;
$iperf{duration} = 60;
$iperf{target_rate} = $target_rate;

#my $cmd = &create_server_args( $iperf );
my $cmd = &create_server_init_cmd( $iperf );
#print "Press enter to start servers...\n";
#<STDIN>;

print "\nStarting servers...\n";
print $sink1 "$cmd";
print $sink2 "$cmd";
print $sink3 "$cmd";


print "Press enter to start clients...\n";
<STDIN>;
#sleep(2);
### initiate clients
my ($sec, $minutes, $hour, $mday, $month, $year, $wday, $yday, $isdst) = gmtime();
my $datetime = sprintf "%4d-%2.2d-%2.2d-%2.2d%2.2d%2.2d", $year+1900,$month+1,$mday,$hour,$minutes,$sec;

printf "Date: $datetime\n";

$iperf{destination} = '195.194.15.10';
$iperf{tos} = 0x20;
$client1_cmd = &create_client_init_cmd( $iperf );

$iperf{destination} = '195.194.15.18';
$iperf{tos} = 0x20;
$client2_cmd = &create_client_init_cmd( $iperf );

$iperf{destination} = '195.194.15.34';
$iperf{tos} = 0;
$client3_cmd = &create_client_init_cmd( $iperf );

#send command out
print $source1 "$client1_cmd";
print $source2 "$client2_cmd";
print $source3 "$client3_cmd";


print "\nConducting test.... please wait.\n";
### does test

sleep( $iperf{duration} + 2 );
print "\n\n===TEST FINISHED===\n";

#printf "CMD=%s, type=%s, port=%d, interval=%d\n", $iperf{CMD}, $iperf{type},$iperf{port}, $iperf{interval};


#### send a get-stats
#$iperf{CMD} = 'GET_STATS';
#my $cmd = &create_server_args( $iperf );
# store all the log files to parse at end
my @sinklogfiles;
my @sourcelogfiles;


my $cmd = &create_get_stats_cmd( $iperf );
#print "Press enter to get statistics...\n";
#<STDIN>;

# store all files in a single directory
$mydir = $target_rate;
`mkdir $mydir \&> /dev/null`;
print "Putting all files in dir: $mydir\n";


# filename format <date>_<source>_<sink>_<flowname>_{source|sink}.log

#flow1 sink
$filename = $mydir . '/' .$datetime . '_' . "128.40.89.244" . '_' . "195.194.15.10" . '_' . $iperf{type} . '_' . 'flow1' . '_' . 'sink.log';

print $sink1 "$cmd";
$iperf_output = <$sink1>;
$iperf_output =~ s/===newline===/\n/g;
open( OUT, ">$filename" );
print OUT "\n$iperf_output\n";
push( @sinklogfiles, $filename );
#flow 1 source
$filename = $mydir . '/' .$datetime . '_' . "128.40.89.244" . '_' . "195.194.15.10" . '_' . $iperf{type} . '_' . 'flow1' . '_' . 'source.log';
print $source1 "$cmd";
$iperf_output = <$source1>;
$iperf_output =~ s/===newline===/\n/g;
open( OUT, ">$filename" );
print OUT "\n$iperf_output\n";
push( @sourcelogfiles, $filename );

#flow2 sink
$filename = $mydir . '/' .$datetime . '_' . "128.40.89.245" . '_' . "195.194.15.18" . '_' . $iperf{type} . '_' . 'flow2' . '_' . 'sink.log';
print $sink2 "$cmd";
$iperf_output = <$sink2>;
$iperf_output =~ s/===newline===/\n/g;
open( OUT, ">$filename" );
print OUT "\n$iperf_output\n";
push( @sinklogfiles, $filename );
#flow 2 source
$filename = $mydir . '/' .$datetime . '_' . "128.40.89.245" . '_' . "195.194.15.18" . '_' . $iperf{type} . '_' . 'flow2' . '_' . 'source.log';
print $source2 "$cmd";
$iperf_output = <$source2>;
$iperf_output =~ s/===newline===/\n/g;
open( OUT, ">$filename" );
print OUT "\n$iperf_output\n";
push( @sourcelogfiles, $filename );

#flow3 sink
$filename = $mydir . '/' .$datetime . '_' . "128.40.89.246" . '_' . "195.194.15.34" . '_' . $iperf{type} . '_' . 'flow3' . '_' . 'sink.log';
print $sink3 "$cmd";
$iperf_output = <$sink3>;
$iperf_output =~ s/===newline===/\n/g;
open( OUT, ">$filename" );
print OUT "\n$iperf_output\n";
push( @sinklogfiles, $filename );
#flow 3 source
$filename = $mydir . '/' .$datetime . '_' . "128.40.89.246" . '_' . "195.194.15.34" . '_' . $iperf{type} . '_' . 'flow3' . '_' . 'source.log';
print $source3 "$cmd";
$iperf_output = <$source3>;
$iperf_output =~ s/===newline===/\n/g;
open( OUT, ">$filename" );
print OUT "\n$iperf_output\n";
push( @sourcelogfiles, $filename );

#print "Sink files: @sinklogfiles\n";
print "Source files: \n";
foreach my $filename (@sourcelogfiles) {
    print '"' . $filename . '"' ."\n";
}


sleep(1);

# summarise the files
iperfCook( $mydir . '/' . 'summary_' . "$target_rate" . '.log', @sourcelogfiles );


#send a end
my $cmd = &create_end_cmd( $iperf );
print "\nPress enter to send $iperf{CMD}...\n";
#<STDIN>;
print $sink1 "$cmd\n";
print $sink2 "$cmd\n";
print $sink3 "$cmd\n";
print $source1 "$cmd\n";
print $source2 "$cmd\n";
print $source3 "$cmd\n";


# and terminate the connection when we're done
#print "Press enter to send close connection...\n";
#<STDIN>;
close($sink1);
close($sink2);
close($sink3);
close( $source1 );
close( $source2 );
close( $source3 );


########################################################################


sub get_filehandle {

  my ( $remote_host, $remote_port ) = @_;

  # assign temp filehandle
  my $fh = FileHandle->new();

  print STDOUT "Attempting to connect to $remote_host:$remote_port... ";
  
  # create a socket
  socket($fh, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
  
  # build the address of the remote machine
  $internet_addr = inet_aton($remote_host)
    or die "Couldn't convert $remote_host into an Internet address: $!\n";
  $paddr = sockaddr_in($remote_port, $internet_addr);
  
  # connect
  connect($fh, $paddr)
    or die "Couldn't connect to $remote_host:$remote_port : $!\n";
  
  # set up autoflushing
  #TO_SERVER->autoflush(1);
  my $old_fh = select( $fh );
  $| = 1;
  select( $old_fh );
  
  print STDOUT "okay\n";

  return $fh;
}







sub start_server {

  my $iperf = $_;



}



sub create_end_cmd {

    my $iperf = $_;

    $iperf{CMD} = "END";

    my $cmd = sprintf "password=%s,CMD=%s", $iperf{password}, $iperf{CMD};

    return $cmd . "\n";

}


sub create_get_stats_cmd {

    my $iperf = $_;

    $iperf{CMD} = "GET_STATS";
    my $cmd = sprintf "password=%s,CMD=%s", $iperf{password}, $iperf{CMD};

    return $cmd . "\n";

}



sub create_server_init_cmd {

    my $iperf = $_;

    $iperf{CMD} = "START";

    # set up defaults
    if( $iperf{packet_size} == '' ) { $iperf{packet_size} = 1472; }
    if( $iperf{report_interval} == '' ) { $iperf{report_interval} = 1; }
  
    my $cmd = sprintf "password=%s,CMD=%s,type=%s,port=%d,socketbuffer=%s,report_interval=%d,packet_size=%d", $iperf{password}, $iperf{CMD}, $iperf{type}, $iperf{port}, $iperf{socketbuffer}, $iperf{report_interval}, $iperf{packet_size};
    
    return $cmd . "\n";
}





sub create_client_init_cmd {

  my $iperf = $_;

  $iperf{CMD} = "START";

  # set up defaults
  if( $iperf{tos} == '' ) { $iperf{tos} = 0; }
  if( $iperf{packet_size} == '' ) { $iperf{packet_size} = 1472; }
  if( $iperf{report_interval} == '' ) { $iperf{report_interval} = 1; }
  if( $iperf{duration} == '' ) { $iperf{duration} = 10; }

  my $cmd = sprintf "password=%s,CMD=%s,type=%s,destination=%s,port=%d,duration=%d,socketbuffer=%s,report_interval=%d,tos=%s", $iperf{password}, $iperf{CMD}, $iperf{type}, $iperf{destination}, $iperf{port}, $iperf{duration}, $iperf{socketbuffer}, $iperf{report_interval},$iperf{tos};

  if( $iperf{type} == 'udp' ) {
      $cmd .= sprintf ",packet_size=%d,target_rate=%s", $iperf{packet_size},$iperf{target_rate};
  }

  return $cmd . "\n";

}





sub iperfCook
{

    my ( $outputfile, @filenames ) = @_;

# filenames format <date>_<source>_<sink>_<protocol>_<flowname>_{source|sink}.log

    # chmod to direcotry?

    my $summary;

    foreach my $file (@filenames) {
	
	my $source_buffer_size= '-';;
	my $sink_buffer_size= '-';;
	my $duration;
	my $time_start = '-';
	my $time_end = '-';
	my $sink_bytes = '-';
	my $source_bytes = '-';
	my $sink_rate = '-';
	my $source_rate = '-';
	my $jitter = '-';
	my $pkts_rcvd = '-';
	my $pkts_sent = '-';
	my $loss = '-';

	
	my ( $date, $source, $sink, $protocol, $flowname, $type ) = split /_/, $file;
	
	( $type , @crap ) = split /\./, $type;
	( $crap, $date ) = split /\//, $date;


	print "file: $file\n";
	# need this or the last file won't open!?
	`cat $filename`;

	# open the source files
	open ( SOURCE, "<$file") or die "Can't open log file $file: $!\n";
	while (<SOURCE>) {
	    
#	    print "  $_";
	    
	    if (/TCP window size: (\d+) Byte/ ) {
		$source_buffer_size = $1 ;
	    }
	    elsif (/UDP buffer size: (\d+) Byte/ ) {
		$source_buffer_size = $1 ;
	    }
	    elsif (/(\d+\.?\d*)\-\s*(\d+\.?\d*)\s+sec\s+(\d+)\s+Bytes\s+(\d+)/ ) {
		$time_start = $1;
		$time_end = $2;
		$sender_bytes = $3;
		$sender_rate = $4;
	    }
	    elsif( /TCP\s{1}port\s+(\d+)/ )
	    {
		$remotePort = $1;
	    }
	    elsif( /UDP port (\d+)/ )
	    {
		$remotePort = $1;
	    }
		
	} #end while
	close ( SOURCE );


	# open the sink file
	$file =~ s/source/sink/;

	print "file: $file\n";

	open ( SINK, "<$file" );
	while (<SINK>) {
	    
	    if ( $protocol eq 'tcp' ) {

		if (/TCP window size: (\d+) Byte/ ) {
		    $sink_buffer_size = $1 ;
		}
		elsif (/(\d+\.?\d*)\-\s*(\d+\.?\d*)\s+sec\s+(\d+)\s+Bytes\s+(\d+)/ ) {
		    $time_start = $1;
		    $time_end = $2;
		    $sink_bytes = $3;
		    $sink_rate = $4;
		}
		
	    }
	    elsif ( $protocol eq 'udp') {

		if (/UDP buffer size: (\d+) Byte/ ) {
		    $sink_buffer_size = $1 ;
		}
		elsif ( /(\d+\.?\d*)\-\s*(\d+\.?\d*)\s+sec\s+(\d+)\s+Bytes\s+(\d+)\s+bits\/sec\s+(\d+\.?\d*)\s+ms\s+(\d+)\/(\d+)\s+\((.*)\%\)/ ) {
		    $time_start = $1;
		    $time_end = $2;
		    $sink_bytes = $3;
		    $sink_rate = $4;
		    $jitter = $5;
		    $pkts_lost = $6;
		    $pkts_sent = $7;
		    $loss = $8;
		#    print "\njitter=$jitter, recv=$pkts_rcvd, sent=$pkts_sent, loss=$loss\n\n";

		}
	    }  else {
		print "ERROR!\n";
	    }


	} #end while

	my $duration = $time_end - $time_start;
    
	my $source_buffer_size = $source_buffer_size / 1024;
	my $sink_buffer_size = $sink_buffer_size / 1024;

	my $sender_mbytes = $sender_bytes / ( 1048576 );
	my $sink_mbytes = $sink_bytes / ( 1048576 );

	my $sender_rate = $sender_rate / 1000000; # convert to mbits from bits
	my $sink_rate = $sink_rate / 1000000; # convert to mbits from bits

        $loss = $pkts_lost / $pkts_sent;

	$summary .= sprintf "$flowname\t$date\t$source\t$sink\t$remotePort\t$protocol\t$source_buffer_size\t$sink_buffer_size\t$duration\t$sender_mbytes\t$sender_rate\t$sink_mbytes\t$sink_rate\t$pkts_sent\t$pkts_lost\t$jitter\t$loss\t";
	$summary .= "\n";


	#print "$summary\n";
    }

    
# write the output file
    open( OUT, ">>$outputfile" );
    
    print OUT "flowname\tdate\tsource\tsink\tsink_port\tprotocol\tsource_socket_buffer\tsink_socket_buffer\tduration\tsender_mbytes_transferred\tsender_rate\trecv_mbytes_transferred\trecv_rate\tpkts_sent\tpkts_lost\tjitter\tloss_rate\n";
    
    print OUT $summary;
    
    close ( OUT );

    print "==================================================\n";
    open( READ, "<$outputfile" );
    while( <READ> ) {
	print $_;
    }
    close( READ );
    print "==================================================\n";
    
}
