use strict;
use IO::Socket::Multicast;
use Getopt::Long::Descriptive;
use Data::Dumper;
use IO::Interface;
use Time::HiRes qw ( time alarm sleep gettimeofday tv_interval );
use IO::Tee;
use POSIX;
my %req = (
"required" => 1
);
my $format = "usage: %c %o\n";
my @opts = (
[ "verbose|V" => "Be noisy" ],
[ "help|h" => "Show help message" ],
[ "rate|r=i" => "Define the update rate to send on the multicast group, this is per second packets" , \%req ],
[ "iface|i=s" => "Interface to use, this can be an ip address or interface name ( ie: eth1 )", \%req ],
[ "addr|a=s" => "Address to use for multicast" , \%req],
[ "port|p=i" => "Port to send to"],
[ "mttl|m=i" => "Max time to live"],
[ "stats=i" => "Statistics printed every 'time' seconds"],
[ "size|s=i" => "size of packets sent"],
[ "log|l=s" => "Logfile to write to, include the path"],
[ "loopback" => "Turn on multicast loopback to local machine, defaultly off"],
[ "time|t" => "only send packets for X time"],
[ "num|n=i" => "Number of packets to send" ]
);
my ($opts, $usage) = describe_options($format,@opts);
$usage->die if ( $opts->{'help'});
#use constant DESTINATION => '226.1.1.2:2000';
die "Bad IP address '",$opts->{"addr"},"\n" if ( $opts->{'addr'} !~ /^((\d|[01]?\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[01]?\d\d|2[0-4]\d|25[0-5])$/ );
$opts->{'port'} = $opts->{'port'} ? $opts->{'port'} : "2000";
$opts->{'size'} = $opts->{'size'} ? $opts->{'size'} :"500";
$opts->{'stats'} = $opts->{'stats'} ? $opts->{'stats'} : "5";
$opts->{'mttl'} = $opts->{'mttl'} ? $opts->{'mttl'} : "2";
$opts->{'num'} = $opts->{'num'} ? $opts->{'num'} : "200";
$opts->{'loopback'} = $opts->{'loopback'} ? "1" : "0";
if ( $opts->{'port'} < 1 || $opts->{'port'} > 65535 ) {
die "Port is not within 1 and 65535, port = ",$opts->{'port'},"\n";
}
my $tee;
if ( $opts->{'log'} ) {
open LOG, ">$opts->{'log'}" or die "Could not open $opts->{'log'} : $!\n";
$tee = IO::Tee->new(\*STDOUT, \*LOG);
}
else {
$tee = IO::Tee->new(\*STDOUT);
print "B\n";
}
$opts->{'trate'} = 1/$opts->{'rate'};
$SIG{'ALRM'} = &alrm_handler;
my $DESTINATION = $opts->{'addr'}.":".$opts->{'port'};
print "Starting to multicast packets.\n";
printf $tee "%20s: %10s\n","Address",$opts->{'addr'};
printf $tee "%20s: %10u\n","Port",$opts->{'port'};
printf $tee "%20s: %10u %-6s\n","Packet Size",$opts->{'size'},"bytes";
printf $tee "%20s: %10u %-6s\n","TTL",$opts->{'mttl'},"hops";
printf $tee "%20s: %10s\n","Loopback",(($opts->{'loopback'}) ? "On" : "Off") ,"\n";
printf $tee "%20s: %10s\n","Rate",$opts->{'rate'},"\n";
my $sock = IO::Socket::Multicast->new(Proto=>'udp',PeerAddr=>$DESTINATION);
$sock->mcast_if($opts->{'iface'}) if ( exists $opts->{'iface'} );
$sock->mcast_ttl($opts->{'mttl'} );
$sock->mcast_loopback( $opts->{'loopback'} ); # should be ok like this ...
my $i = 1;
# Start timing!
my $t0 = [gettimeofday()];
while ($i <= $opts->{'num'} ) {
my $message = "$i\n"; #localtime;
# $message .= "\n $i\n";
$sock->send($message) || die "Couldn't send: $!";
$i++;
} continue {
# sleep $opts->{'trate'};
}
my $t0_t1 = tv_interval($t0);
print "$opts->{'num'} in $t0_t1 seconds\n";
print $opts->{'num'}/$t0_t1," pps\n";
close LOG;
# this is our sub-second event handler, requires Time::HiRes to work -- let's hope it spins fast using alarm() !! :-/
# write it after determining how this one runs
sub alrm_handler {
}