#!/usr/local/bin/perl

# packet test
# on server: ptest.pl -s
# on client: ptest.pl -c -h <server_addr> -n 10000

use strict;
use Getopt::Std;
use IO::Socket::INET;
use Time::HiRes qw(usleep);

my %opt;
getopts('Dh:p:scn:t:', \%opt);
# Debug
# host of server
# port on server
# server mode
# client mode
# number of packets to send
# time between packets (microseconds, us)

$opt{p} ||= 6932;
$opt{t} ||= 90;

if( $opt{s} ){
	my $sock = IO::Socket::INET->new(LocalPort  => $opt{p},
                                         Proto      => 'udp',
                                        )
          or die "Can't bind : $@\n";

	my $rcvd=0;
	my $expect=1;
	my $mtotal=0;
	while(1){
		my $payload;
		$sock->recv( $payload, 1500 );
		my ($id) = $payload =~ /packet (\d+)/;
		if( $id eq '0' ){
			verbose( "got BEGIN packet" );
			$expect=1;
			$rcvd=0;
			$mtotal=0;
			next;
		}elsif( $id eq '00' ){
			verbose( "got END packet: received: $rcvd - missed: $mtotal" );
			next;
		}
		$rcvd++; # dont count for begin/end

		if( $id > $expect ){
			# we missed packet(s)
			my $missed = ($id-$expect);
			$mtotal += $missed;
			verbose( "missed $missed packets (got: $id - expected: $expect)" );
			$expect += $missed + 1;
		}elsif( $id == $expect ){
			debug( "got packet: $id" );
			unless( $rcvd % 1000 ){
				verbose( "received $rcvd packets" );
			}
			$expect++;
		}else{
			debug( "error: id: $id - expect: $expect - rcvd: $rcvd" );
		}
	}
}elsif( $opt{c} ){
	$opt{h} || die "specify -h <hostname>\n";
	
	if( $opt{l} > 1500 ){
		die "will not send packet larger than mtu.\n";
	}

	my $sock = IO::Socket::INET->new(PeerAddr   => $opt{h},
                                         PeerPort   => $opt{p},
                                         Proto      => 'udp',
                                        )
          or die "Can't bind : $@\n";

	$sock->send('packet 0'); # BEGIN

	for( 1..$opt{n} ){
		debug( "sending packet $_" );
		unless( $_ % 1000 ){
			verbose( "sent $_/$opt{n} packets" );
		}

		$sock->send( "packet $_" );
		usleep($opt{t}) if $opt{t};
	}

	$sock->send('packet 00');  # END
}else{
	die "specify mode: -s or -c\n";
}

sub verbose {
	my $msg = join('', @_);

	warn "$msg\n";
}

sub debug {
	verbose @_ if $opt{D};
}
