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 { }