http://paperlined.org/dev/src/pl/ping_cable_modem.pl
#!/usr/bin/perl
# This launches a bunch of different commands in different Screen windows, so that they all display
# at once.
# http://en.wikipedia.org/wiki/GNU_Screen
#
#
# Remember, to exit Screen, use ctrl-A \
use strict;
use warnings;
use File::Temp;
use IO::BufferedSelect;
use Data::Dumper;
my $interface = "eth1";
our @windows_to_open = (
[$0, "arping", "-I", $interface, "192.168.1.199"],
[$0, "arping", "-I", $interface, "192.168.1.254"],
[$0, "ping", "99.140.223.254"],
[$0, "ping", "4.2.2.2"],
[$0, "dig", "google.com", "192.168.1.254", "+time=2"],
);
if ($ENV{RECORD_SCREEN_PID}) {
open my $fout, ">$ENV{RECORD_SCREEN_PID}" or die $!;
print $fout getppid();
close $fout;
}
# are we running inside Screen?
if ($ENV{WINDOW}) {
# if so, set up a Ctrl-C handler that will kill ALL screen windows, as soon as any one of them is killed
$SIG{INT} = sub {
my $screen_pid = getppid();
system "screen", "-x", $screen_pid, "-X", "quit";
}
}
# to start this script normally, don't use any command-line parameters
if (!@ARGV) {
# Arping really requires root. So restart as root if we need to.
$> == 0 or exec "sudo", $0;
launch_multiwindow();
# if command-line parameters are sent, then we run the specific sub-command
} else {
# update the title of this window
my $title = join(" ", @ARGV);
print "\ek$title\e\\";
#if ($ENV{WINDOW} == 0) {
#sleep(1); # delay JUST a little, because the "resize =" command we run has a tendency to chop off a few lines otherwise
select(undef,undef,undef,0.4);
#}
my $cmd = shift @ARGV;
if ($cmd eq 'wait') {
foreach (1..999) {
print "waiting.... $_\n";
sleep 1;
}
exit;
} elsif ($cmd eq 'ping') {
ping("ping", @ARGV);
exit;
} elsif ($cmd eq 'arping') {
arping("arping", @ARGV);
exit;
} elsif ($cmd eq 'dig') {
dig("dig", @ARGV);
sleep 100;
exit;
} else {
print "Unknown command: ", Dumper [$cmd, @ARGV];
sleep 100;
exit;
}
}
sub launch_multiwindow {
my ($fh, $screen_pid_tempfile) = File::Temp::tempfile();
close $fh;
# run screen, and tell screen to run us, and when it runs us, tell ourselves to record the $PPID into $screen_pid_tempfile
$ENV{RECORD_SCREEN_PID} = $screen_pid_tempfile;
# the first window gets started a little differently... it gets started when the main screen PID gets started
my $first_window = shift(@windows_to_open);
my $screen_pid = fork();
if ($screen_pid == 0) {
exec "screen", @$first_window;
}
# Wait for the pid file to be written to by the first screen
my $deadline = time() + 2;
while (time() <= $deadline) {
last if (-s $screen_pid_tempfile);
select undef, undef, undef, 0.25;
}
-s $screen_pid_tempfile or die "Unable to find Screen's PID\n";
# for some reason, $screen_pid isn't the one that we can use for '-x'...
# $real_screen_pid ends up being one of the immediate children of $screen_pid
my $real_screen_pid = catfile($screen_pid_tempfile);
my @screen_command = ("screen", "-x", $real_screen_pid, "-X");
my @create_new_window = (@screen_command, "screen", "1");
foreach my $window_command (@windows_to_open) {
system @screen_command, "split";
system @screen_command, "focus", "down";
system @create_new_window, @$window_command;
}
system @screen_command, "resize", "="; # make all regions equally high
waitpid($screen_pid, 0);
exit;
}
# like normal 'ping', but with a little wrapper around it to display the time that a packet was printed
sub ping {
my (@ping_arguments) = @_;
open my $pin, "-|", @ping_arguments or die $!;
my $host = $ping_arguments[-1]; # just assume/guess wildly, that it's the last argument
while (defined(local $_ = foreach_bufferedselect($pin, 2))) {
if (ref($_)) {
print scalar(localtime), " timed out ($host)\n";
next;
}
chomp;
print scalar(localtime()), " $_\n";
}
exit; # EOF
}
# apt-get install arping
sub arping {
my (@arping_arguments) = @_;
open my $pin, "-|", @arping_arguments or die $!;
while (defined(local $_ = foreach_bufferedselect($pin, 2))) {
if (ref($_)) {
print scalar(localtime), " timed out\n";
} else {
print;
}
}
}
sub dig {
my (@dig_arguments) = @_;
while (1) {
my $start_time = localtime();
open my $pin, "-|", @dig_arguments or do {print $!; sleep 100; exit};
my @query_times;
my $total_query_time = 0;
my $last_was_question = 0;
my $queried_for = '';
my $timed_out;
while (<$pin>) {
if (/query time: (\d+)/i) {
push(@query_times, $1);
$total_query_time += $1;
}
if (/connection timed out/i) {
$timed_out++;
}
if ($last_was_question && !$queried_for) {
($queried_for) = split ' ', $_;
$queried_for =~ s/^;|\.$//g;
}
$last_was_question = 0;
$last_was_question = 1 if (/QUESTION SECTION/);
}
close $pin;
#print "$start_time --- ", join(" ", @query_times), "\n";
#print "$start_time --- $total_query_time --- ", join(" ", @dig_arguments), "\n";
if ($timed_out) {
print "$start_time --- timeout\n";
next;
}
print "$start_time --- $queried_for --- $total_query_time\n";
my $remainder = 1000 - $total_query_time; # milliseconds left to sleep
if ($remainder > 0) {
#sleep($remainder/1000);
select undef, undef, undef, $remainder/1000;
}
#sleep(2 - $total_query_time/1000);
}
}
sub catfile {
my ($filename) = @_;
-f $filename or return undef;
open my $fin, "<$filename" or die $!;
my @ret = wantarray ? <$fin> : do {local $/=undef; <$fin>};
close $fin;
wantarray ? @ret : $ret[0];
}
BEGIN {
# This is a "simple" wrapper around IO::BufferedSelect.
#
# It's intended to be used in cases where you just want to do a while (<$fh>)
# read loop for ONE handle, and the only reason you're using
# IO::BufferedSelect is to add the ability to do timeouts for that one
# handle.
#
# It returns three possible values:
# - a scalar, if a line was returned
# - undef, if EOF was encountered
# - an array-ref (with just one element -- undef) if a timeout occurred
my %foreach_bufferedselect;
sub foreach_bufferedselect {
my ($fh, $timeout) = @_;
my $fileno = fileno($fh);
my $data;
if (!exists $foreach_bufferedselect{$fileno}) {
$data = $foreach_bufferedselect{$fileno} = {};
$data->{bs} = new IO::BufferedSelect($fh);
$data->{accum} = [];
} else {
$data = $foreach_bufferedselect{$fileno};
}
if (@{ $data->{accum} }) {
my $line = shift( @{ $data->{accum} } );
return _foreach_bufferedselect_ret_one($line);
}
my $buf_select = $data->{bs};
$data->{accum} = [ $buf_select->read_line($timeout) ];
if ( @{$data->{accum}} == 0 ) {
my $array_ref = [undef];
return $array_ref; # return-type: timed-out
} else {
my $line = shift( @{ $data->{accum} } );
return _foreach_bufferedselect_ret_one($line);
}
}
# we have one value from the array... figure out what to return to the caller of foreach_bufferedselect()
sub _foreach_bufferedselect_ret_one {
my $line = shift;
if (!defined($line->[1])) {
return undef; # return-type: EOF
} else {
return $line->[1]; # return-type: text contents of a line
}
}
}
Generated by GNU enscript 1.6.4.