Wiki Socket Protocol Description
The Moab scheduler uses a simple protocol for socket connections
to the user client and the resource manager as described below:
<SIZE><CHAR>CK=<CKSUM><WS>TS=<TIMESTAMP><WS>AUTH=<AUTH><WS>DT=<DATA>
<SIZE>
|
8 character decimal ASCII representation of the size of the
packet following '<SIZE><CHAR>' Leading zeroes must be used
to pad this value to 8 characters if necessary.
|
<CHAR>
|
A single ASCII character
|
<CKSUM>
|
A 16 character hexadecimal ASCII DES-based checksum
calculated using the algorithm below* and <SEED> selected
and kept secret by the site admins. The checksum is
performed on the line from 'TS=' to the end of the message
including <DATA>.
|
<WS>
|
a series of 'white space' characters consisting of either
'tabs' and/or 'space' characters.
|
<TIMESTAMP>
|
ASCII representation of epoch time
|
<AUTH>
|
Identifier of user requesting service (i.e., USERNAME)
|
<DT>
|
Data to be sent
|
An example header follows:
00001057 CK=cdf6d7a7ad45026f TS=922401962 AUTH=sched DT=<DATA>
where '<DATA>' is replaced by actual message data.
Checksum Algorithm ('C' version)
#define MAX_CKSUM_ITERATION 4
int GetChecksum(
char *Buf,
int BufSize,
char *Checksum,
char *CSKey) /* Note: pass in secret key */
{
unsigned int crc;
unsigned int lword;
unsigned int irword;
int index;
unsigned int Seed;
Seed = (unsigned int)strtoul(CSKey,NULL,0);
crc = 0;
for (index = 0;index < BufSize;index++)
{
crc = (unsigned int)DoCRC((unsigned short)crc,Buf[index]);
}
lword = crc;
irword = Seed;
PSDES(&lword,&irword);
sprintf(Checksum,"%08x%08x",
lword,
irword);
return(SUCCESS);
}
unsigned short DoCRC(
unsigned short crc,
unsigned char onech)
{
int index;
unsigned int ans;
ans = (crc ^ onech << 8);
for (index = 0;index < 8;index++)
{
if (ans & 0x8000)
ans = (ans <<= 1) ^ 4129;
else
ans <<= 1;
}
return((unsigned short)ans);
}
int PSDES(
unsigned int *lword,
unsigned int *irword)
{
int index;
unsigned int ia;
unsigned int ib;
unsigned int iswap;
unsigned int itmph;
unsigned int itmpl;
static unsigned int c1[MAX_CKSUM_ITERATION] = {
0xcba4e531, 0x537158eb, 0x145cdc3c, 0x0d3fdeb2 };
static unsigned int c2[MAX_CKSUM_ITERATION] = {
0x12be4590, 0xab54ce58, 0x6954c7a6, 0x15a2ca46 };
itmph = 0;
itmpl = 0;
for (index = 0;index < MAX_CKSUM_ITERATION;index++)
{
iswap = *irword;
ia = iswap ^ c1[index];
itmpl = ia & 0xffff;
itmph = ia >> 16;
ib = (itmpl * itmpl) + ~(itmph*itmph);
ia = (ib >> 16) | ((ib & 0xffff) << 16);
*irword = (*lword) ^ ((ia ^ c2[index]) + (itmpl * itmph));
*lword = iswap;
}
return(SUCCESS);
}
Header Creation (PERL code)
(taken from PNNL's QBank client code)
################################################################################
#
# subroutine wiki($COMMAND)
#
# Sends command to Moab server and returns the parsed result and status
#
################################################################################
sub wiki
{
my($COMMAND,$REQUEST,$result);
my($sockaddr,$hostname);
my($name,$aliases,$proto,$port,$type,$len,$thisaddr);
my($thisport,$thatport,$response,$result);
$COMMAND = shift;
#
# Establish socket connection
#
$sockaddr = 'S n a4 x8';
chop ($hostname = `hostname`);
($name,$aliases,$proto)=getprotobyname('tcp');
($name,$aliases,$type,$len,$thisaddr)=gethostbyname($hostname);
($name,$aliases,$type,$len,$thataddr)=gethostbyname($BANKHOST);
$thisport=pack($sockaddr, &AF_INET,0,$thisaddr);
$thatport=pack($sockaddr, &AF_INET,$BANKPORT,$thataddr);
socket(S, &PF_INET,&SOCK_STREAM,$proto) || die "cannot create socket\n";
bind(S,$thisport) || die "cannot bind socket\n";
connect(S,$thatport) || die "cannot connect socket\n";
select(S); $| = 1; # Turn on autoflushing
select(stdout); $| = 1; # Select STDOUT as default output
#
# Build and send command
#
$REQUEST="COMMAND=$COMMAND AUTH=$AUTH";
chomp($CHECKSUM = `$QSUM "$REQUEST"`);
$REQUEST .= " CHECKSUM=$CHECKSUM";
my $command=pack "a8 a1 A*",sprintf("%08d",length($REQUEST))," ",$REQUEST;
print S "$command"; # Send Command to server
@REPLY=();
while () { push(@REPLY,$_); } # Listen for Reply
$STATUS=grep(/STATUSCODE=(\d*)/&&$1,@REPLY); # STATUSCODE stored in $STATUS
grep(s/.*RESULT=//,@REPLY); # Parse out the RESULT
return @REPLY;
}
Header Processing (PERL code)
sysread(NS,$length,8); # Read length string
sysread(NS,$delimiter,1); # Read delimiter byte
$DEBUG && print STDERR "length=[$length]\tdelimiter=[$delimiter]\n";
while($length) {
$DEBUG && print STDERR "Awaiting $length bytes -- ".`date`;
$length-=sysread(NS,$request,$length); # Read request
sleep 1;
}
%REQUEST=();
chomp($request);
foreach (@REQUEST=&shellwords($request)) # Parse arguments into array
{
($key,$value)=split(/=/,$_);
$REQUEST{$key}=$value unless defined $REQUEST{$key};
}
$request =~ s/\s+CHECKSUM=.*//; # Strip off the checksum
print STDERR "REQUEST=$request\n";
chomp($checksum=`$QSUM "$request"`);
$me=$REQUEST{AUTH};
$command=$REQUEST{COMMAND};
if (!grep($command eq $_,@VALIDCMDS))
{ $REPLY = "STATUSCODE=0 RESULT=$command is not a valid command\n";}
elsif ($checksum ne $REQUEST{CHECKSUM})
{ $REPLY = "STATUSCODE=0 RESULT=Invalid Checksum\n";}
else
{ $REPLY = do $command(@REQUEST); }
$len=sprintf("%08d",length($REPLY)-1);
$delim=' ';
$DEBUG && print STDERR "REPLY=${len}${delim}$REPLY\n";
$buf="$len"."$delim"."$REPLY";
syswrite(NS,$buf,length($buf));
close NS;