#!/usr/bin/env perl
#
# Description: puts out a UDP message on port 40000 to wafer pc104 to VBNC.exe,
#              which then issues the win98 shutdown command
#
###############################################################################
use IO::Socket;
use IO::Select;
use Sys::Hostname;
use Net::Ping;
use Switch;
use Time::HiRes qw( usleep);
use strict;

# turn off stdout autobuffering
$| = 1;


# arg parsing
my ($local, $host);
switch ($#ARGV) {
  case -1 { $host = hostname() }
  case 0 {  $host = $ARGV[0] }
  else {
    print "usage: ./wafer-shutdown host\n";
    print "where host = wafer28, wafer28-wifi, wafer31, or wafer31-wifi\n";
    exit(-1);
  }
}

# host parsing
my $WAFER28      = "192.168.2.128";
my $WAFER28_WIFI = "192.168.1.128";
my $WAFER31      = "192.168.2.131";
my $WAFER31_WIFI = "192.168.1.131";
my $wafer_ip;
if ($host eq "wafer28" or $host eq "wafer28-wifi" or $host eq "iver28") {
  if (hostname() eq "iver28") { #use local LAN
    $wafer_ip = $WAFER28;
  }
  else {
    $wafer_ip = $WAFER28_WIFI;
  }
}
elsif ($host eq "wafer31" or $host eq "wafer31-wifi" or $host eq "iver31") {
  if (hostname() eq "iver31") { #use local LAN
    $wafer_ip = $WAFER31;
  }
  else {
    $wafer_ip = $WAFER31_WIFI;
  }
}
else {
  print "usage: ./wafer-shutdown host\n";
  print "where host = wafer28, wafer28-wifi, wafer31, or wafer31-wifi\n";
  exit(-1);
}


print "\rshutting down wafer\n";
my $ticks = 0;
my $TIMEOUT = 45;
my $noping = 0;
my $ack = 0;
my $reply = "";
my $timeout = 1;
my $p = Net::Ping->new() or die "$!";
for ($ticks=1; $ticks <= $TIMEOUT; $ticks++) {

  # build outgoing shutdown msg and send it
  my $cmd = "VBN SHUTDOWN";
  my $lport = "40001";
  my $sockout = IO::Socket::INET->new(Proto => 'udp',
                                      PeerPort => "40000",
                                      PeerAddr => $wafer_ip,
                                      LocalPort => $lport,
                                      Type => SOCK_DGRAM) or die "$!";
  $sockout->send($cmd);
  $sockout->close();

  # check for ack
  my $wait = 0.25;
  my $sockin = IO::Socket::INET->new(Proto => 'udp',
                                     LocalPort => $lport) or die "$!";
  my @ready = IO::Select->new($sockin)->can_read($wait);
  if (@ready) {
    $sockin->recv($reply, 256);
    if ($reply eq $cmd) {
      $ack = 1;
      last;
    }
  }
  $sockin->close();

  if (0) { # fancy 1 second twirler
    my $NSPINS = 12;
    for (my $i=0; $i < $NSPINS; $i++) {
      switch ($i % 4) {
        case 0 { print "|" }
        case 1 { print "/" }
        case 2 { print "-" }
        case 3 { print "\\" }
        else   { print "." }
      }
      usleep((1-$wait)*1000000/$NSPINS);
      print "\b";
    }
  }
  else {
    usleep((1-$wait)*1000000);
  }

  if ($ticks==0 || $ticks % 10) {
    print ".";
  }
  else {
    print "$ticks";
  }

  if (!$p->ping($wafer_ip) ) {
    $noping = 1;
    last;
  }
  elsif ( $ack ) {
    last;
  }

} # end: for ()

my $ret;
if ($ticks > $TIMEOUT) {
  print "\bTIMEOUT\n";
  print "error: wafer not shutting down, is VBNC.exe running?\n";
  $ret = -1;
}
elsif ($noping) {
  print "\bNOT PINGING\n";
  $ret = 0;
}
elsif ($ack) {
  print "\b$reply\n";
  $ret = 1;
}


$p->close();


exit($ret);
