Commit e335015b authored by Leigh B. Stoller's avatar Leigh B. Stoller

Changes to sync protocol. The RPC27 spits out a bunch of silly status

goo whenever it goes inactive for more than a couple of minutes. Also,
require that we sync up so that we know for sure that the power
control failed. Previously, I was blindly spitting out the command
without being sure we had a command prompt.

Note, that we still have a problem with an active tip session messing
up power control since only one connection can be active at a time.
At present, there is no positive way to know that the connection was
refused since capture accepts the connection and then closes it if
there is an active tip session. I need to change the little handshake
so that there is a response Yes/Know response to the secret key
exchange.
parent 893a917f
......@@ -25,7 +25,7 @@ use libdb;
$| = 1;
# Set for more output.
my $debug = 0;
my $debug = 1;
# RPC27 Prompt string
my $RPC27_PROMPT = "RPC-27>";
......@@ -39,51 +39,86 @@ my %RPC27_CMD =
# cmd = { "cycle" | "on" | "off" }
# controller = <node_id>
# outlet = int, 1 <= outlet <= 20
#
# Returns 0 on success. Non-zero on failure.
#
sub rpc27ctrl {
my($cmd, $controller, $outlet) = @_;
my($TIP, $i);
my($TIP, $i, $insync);
if ( $outlet < 1 || $outlet > 20 ) {
print STDERR "*** Invalid outlet '$outlet': Must be 1-20\n";
return 1;
}
#
# Form the connection to the controller via a "tip" line to the
# capture process. Once we have that, we can just talk to the
# controller directly.
#
if (! ($TIP = tipconnect($controller))) {
print STDERR "*** Could not form TIP connection to $controller\n";
return 1;
}
if ( $outlet < 1 || $outlet > 20 ) {
print STDERR "*** Invalid outlet '$outlet': Must be 1-20\n";
return 1;
}
#
# Send a couple of newlines to get the command prompt, and then wait
# for it to print out the command prompt. This loop is set for a small
# number since if it cannot get the prompt quickly, then something has
# gone wrong/
print $TIP "\r\n";
for ($i = 0; $i < 5; $i++) {
my $line = <$TIP>;
if ($debug) { print "Read: $line"; }
if ($line =~ /^$RPC27_PROMPT/) {
if ($debug) { print "Matched prompt '$RPC27_PROMPT'!\n"; }
# gone wrong.
#
$insync = 0;
for ($i = 0; $i < 10; $i++) {
my $line;
if (syswrite($TIP, "\r\n") == 0) {
print STDERR
"*** Power control sync failed ($controller/$outlet)\n";
close($TIP);
return 1;
}
if (sysread($TIP, $line, 1024) == 0) {
last;
}
if ($debug) {
print "Read: $line";
}
if ($line =~ /$RPC27_PROMPT/) {
if ($debug) {
print "Matched prompt '$RPC27_PROMPT'!\n";
}
$insync = 1;
last;
}
print $TIP "\r\n";
}
# Okay, got a prompt. Send it the string:
print $TIP "$RPC27_CMD{$cmd} $outlet\r\n";
if (! $insync) {
print STDERR "*** Could not sync with power controller! ".
"($controller/$outlet)\n";
close($TIP);
return 1;
}
if ($debug) {
print "Sending '$RPC27_CMD{$cmd} $outlet'...\n";
print "rpc27ctrl: Sent $cmd command to outlet $outlet on $controller.\n";
print "Sending '$RPC27_CMD{$cmd} $outlet' to $controller\n";
}
# Okay, got a prompt. Send it the string:
if (syswrite($TIP, "$RPC27_CMD{$cmd} $outlet\r\n") == 0) {
print STDERR "*** Power control write failed ($controller/$outlet)\n";
close($TIP);
return 1;
}
close($TIP);
return 0;
}
#
# Connect up to the capture process. This should probably be in a library
# someplace.
#
sub tipconnect($) {
my($controller) = $_[0];
my($server, $portnum, $keylen, $keydata);
......@@ -96,7 +131,7 @@ sub tipconnect($) {
if ($query_result->numrows < 1) {
print STDERR "*** No such tipline: $controller\n";
return 1;
return 0;
}
%powerid_row = $query_result->fetchhash();
......@@ -109,6 +144,12 @@ sub tipconnect($) {
print "tipconnect: $server $portnum $keylen $keydata\n";
}
#
# We have to send over the key. This is a little hokey, since we have
# to make it look like the C struct.
#
my $secretkey = pack("iZ256", $keylen, $keydata);
#
# This stuff from the PERLIPC manpage.
#
......@@ -119,29 +160,43 @@ sub tipconnect($) {
$paddr = sockaddr_in($portnum, $inetaddr);
$proto = getprotobyname('tcp');
if (! socket(TIP, PF_INET, SOCK_STREAM, $proto)) {
print STDERR "*** Cannot create socket.\n";
return 0;
}
#
# We have no locking protocol in place for the tiplines. So, loop
# a small number of time, trying to form a proper connection.
#
for ($i = 0; $i < 10; $i++) {
if (! socket(TIP, PF_INET, SOCK_STREAM, $proto)) {
print STDERR "*** Cannot create socket.\n";
return 0;
}
if (! connect(TIP, $paddr)) {
print STDERR
"*** Cannot connect to $controller on $server($portnum)\n";
return 0;
}
TIP->autoflush(1);
# Okay, we got a connection. We have to send over the key. This is a
# little hokey, since we have to make it look like the C struct.
my $secretkey = pack("iZ256", $keylen, $keydata);
if (! syswrite(TIP, $secretkey)) {
if (! connect(TIP, $paddr)) {
print STDERR
"*** Cannot connect to $controller on $server($portnum)\n";
return 0;
}
TIP->autoflush(1);
#
# If the connect succeeds, but the write fails, it means that the
# other end dropped the connection cause there was already a tip
# active (either a person on the tip line, or another power control).
#
# I'm not happy about this. We need a more positive action protocol.
#
if (syswrite(TIP, $secretkey) > 0) {
return(*TIP);
}
print STDERR
"*** Cannot write key to $controller on $server($portnum)\n";
return 0;
"*** WARNING: Cannot write to $controller on $server($portnum)" .
" Power controller might be busy. Waiting a bit ...\n";
close(TIP);
}
return(*TIP);
print STDERR
"*** Cannot connect to $controller on $server($portnum)\n";
return 0;
}
1;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment