-- Copyright (C) 1983, 1984 by Xerox Corporation. All rights reserved.
-- HostWatcherPoke.mesa, HGM, 25-Nov-84 10:08:11
DIRECTORY
Ascii USING [CR, LF, SP],
Heap USING [systemZone],
Stream USING [Delete, GetChar, Handle, PutChar, SendNow, TimeOut],
String USING [
AppendString, AppendChar, AppendLongDecimal, WordsForString, EquivalentString],
System USING [gmtEpoch],
Time USING [Current],
OldLibrarian USING [PropertyList, PropertyPair, PropertyNumber],
OldLibrarianPN USING [IDName, StringName],
OldLibrarianOps USING [LibjectMessage, LibjectMessageType, ValidLibrarianMessage],
STP USING [Create, Destroy, Error, Handle, Open],
Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer],
GateControlDefs USING [
gateControlStatsSend, gateControlStatsAck, GateControlStatsEntry],
HostWatcherOps USING [Info, ShowErrorPup, State],
PopCorn USING [Error, GetClockOffset],
PupDefs USING [
PupBuffer, PupSocket, PupSocketDestroy,
PupSocketMake, SecondsToTocks, SetPupContentsWords, GetPupContentsBytes,
veryLongWait],
PupStream USING [PupByteStreamCreate, StreamClosing],
PupTypes USING [fillInSocketID, PupAddress, PupType],
PupWireFormat USING [BcplLongNumber, BcplToMesaLongNumber];
HostWatcherPoke: PROGRAM
IMPORTS
Heap, Stream, STP, String, Time,
Buffer, PupWireFormat, PopCorn, PupDefs, PupStream,
HostWatcherOps
EXPORTS HostWatcherOps =
BEGIN OPEN PupDefs, PupTypes;
z: UNCOUNTED ZONE = Heap.systemZone;
Info: TYPE = HostWatcherOps.Info;
debug: BOOLEAN ← FALSE;
PokeGateway: PUBLIC PROCEDURE [info: Info] =
BEGIN
pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 2];
soc: PupSocket ← PupSocketMake[fillInSocketID, info.address, SecondsToTocks[5]];
b: PupBuffer ← NIL;
packetNumber: CARDINAL ← NextSequenceNumber[];
tries: CARDINAL ← 10;
THROUGH [0..tries) DO
b ← Buffer.GetBuffer[pup, pool, send];
b.pup.pupID.a ← 27182;
b.pup.pupID.b ← (packetNumber ← packetNumber + 1);
b.pup.pupType ← GateControlDefs.gateControlStatsSend;
SetPupContentsWords[b, 0];
soc.put[b];
UNTIL (b ← soc.get[]) = NIL DO
SELECT TRUE FROM
(b.pup.pupType = error AND b.pup.errorCode = noProcessPupErrorCode) =>
BEGIN
i: CARDINAL;
FOR i IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.pup.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pup.pupType = error) => HostWatcherOps.ShowErrorPup[b];
(b.pup.pupType = GateControlDefs.gateControlStatsAck)
AND (b.pup.pupID.b = packetNumber) =>
BEGIN
gse: LONG POINTER TO GateControlDefs.GateControlStatsEntry;
oldStartTime: LONG CARDINAL ← info.startTime;
i: CARDINAL;
gse ← LOOPHOLE[@b.pup.pupBody];
FOR i IN [0..gse.versionText.length) DO
String.AppendChar[info.text, gse.versionText.char[i]]; ENDLOOP;
AppendUpTime[info.text, gse.startTime];
info.startTime ← [PupWireFormat.BcplToMesaLongNumber[gse.startTime]];
IF oldStartTime # System.gmtEpoch
AND (info.startTime > (oldStartTime + 2*60)) THEN GOTO Restarted;
GOTO Up;
END;
ENDCASE => NULL;
Buffer.ReturnBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Up => info.state ← up;
Restarted => info.state ← restarted;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN Buffer.ReturnBuffer[b];
PupSocketDestroy[soc];
Buffer.DestroyPool[pool];
END;
AppendUpTime: PROCEDURE [
s: LONG STRING, startTime: PupWireFormat.BcplLongNumber] =
BEGIN
now, then: LONG INTEGER;
sec: LONG INTEGER;
min: LONG INTEGER;
hours: LONG INTEGER;
String.AppendString[s, " up "L];
then ← PupWireFormat.BcplToMesaLongNumber[startTime];
now ← Time.Current[];
sec ← now - then;
IF sec < 0 THEN
BEGIN -- Startup glitch
sec ← -sec;
String.AppendChar[s, '-];
END;
hours ← sec/3600;
sec ← sec - hours*3600;
min ← sec/60;
sec ← sec - min*60;
String.AppendLongDecimal[s, hours];
String.AppendChar[s, ':];
IF min < 10 THEN String.AppendChar[s, '0];
String.AppendLongDecimal[s, min];
String.AppendChar[s, ':];
IF sec < 10 THEN String.AppendChar[s, '0];
String.AppendLongDecimal[s, sec];
END;
PokeChat: PUBLIC PROCEDURE [info: Info] =
BEGIN
sh: Stream.Handle ← NIL;
state: HostWatcherOps.State ← up;
BEGIN
ENABLE
BEGIN
PupStream.StreamClosing =>
BEGIN
IF text # NIL THEN String.AppendString[info.text, text];
SELECT why FROM
transmissionTimeout => state ← timeout;
remoteReject => state ← rejecting;
ENDCASE =>
BEGIN
LookAtThis: SIGNAL = CODE;
IF debug THEN SIGNAL LookAtThis;
state ← unknown;
END;
IF CheckForFull[info.text] THEN state ← full;
CONTINUE;
END;
Stream.TimeOut => {state ← timeout; CONTINUE; };
END;
sh ← PupStream.PupByteStreamCreate[info.address, PupDefs.veryLongWait];
IF sh # NIL THEN
BEGIN
Stream.PutChar[sh, Ascii.CR]; -- Krock for Vaxc
Stream.SendNow[sh];
DO
c: CHARACTER;
c ← Stream.GetChar[sh];
IF c = Ascii.LF THEN LOOP;
IF c = Ascii.SP AND info.text.length = 0 THEN LOOP; -- More Vaxc krockery
IF c = Ascii.CR THEN {IF info.text.length = 0 THEN LOOP ELSE EXIT; };
String.AppendChar[info.text, c];
ENDLOOP;
END;
END;
IF sh # NIL THEN Stream.Delete[sh];
info.state ← state;
END;
CheckForFull: PROCEDURE [text: LONG STRING] RETURNS [full: BOOLEAN] =
BEGIN
IF String.EquivalentString[text, "RFC Refused"L] THEN RETURN[TRUE]; -- Alto: FTP.run
IF String.EquivalentString[text, "Server full, try again later"L] THEN
RETURN[TRUE]; -- Maxc
IF String.EquivalentString[text, "No dial-out lines available"L] THEN
RETURN[TRUE]; -- DLS
IF String.EquivalentString[text, "Line is busy"L] THEN RETURN[TRUE]; -- DLS, specific port
IF String.EquivalentString[text, "Server is full"L] THEN RETURN[TRUE]; -- Juniper
IF String.EquivalentString[text, "IFS is full - try later"L] THEN
RETURN[TRUE];
IF String.EquivalentString[text, "Server full"L] THEN RETURN[TRUE]; -- Grapevine
IF String.EquivalentString[text, "Sorry, we are full now"L] THEN RETURN[TRUE];
-- Gateway
RETURN[FALSE];
END;
PokeFtp: PUBLIC PROCEDURE [info: Info] =
BEGIN
state: HostWatcherOps.State ← up;
handle: STP.Handle ← NIL;
herald: LONG STRING ← NIL;
handle ← STP.Create[];
herald ← STP.Open[handle, info.name !
STP.Error =>
BEGIN
SELECT code FROM
connectionRejected => state ← rejecting;
connectionTimedOut => state ← timeout;
ENDCASE => state ← unknown;
String.AppendString[info.text, error];
CONTINUE;
END ];
String.AppendString[info.text, herald];
z.FREE[@herald];
info.state ← state;
[] ← STP.Destroy[handle];
END;
PokeMail: PUBLIC PROCEDURE [info: Info] =
BEGIN
info.state ← unknown;
END;
PokeLibrarian: PUBLIC PROCEDURE [info: Info] =
BEGIN OPEN OldLibrarian, OldLibrarianPN, OldLibrarianOps;
pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 2];
soc: PupSocket ← PupSocketMake[fillInSocketID, info.address, SecondsToTocks[15]];
request: LibjectMessageType = FindID;
b: PupBuffer;
message: LONG POINTER TO LibjectMessage;
plist: LONG POINTER TO ARRAY [0..2) OF PropertyPair;
transactionID: CARDINAL ← NextSequenceNumber[];
FOR i: CARDINAL IN [0..5) DO
b ← Buffer.GetBuffer[pup, pool, send];
b.pup.pupID ← [transactionID, i];
message ← LOOPHOLE[@b.pup.pupWords];
message.id ← transactionID;
message.password ← ValidLibrarianMessage;
message.type ← request;
message.plist ← DESCRIPTOR[NIL, 2];
plist ← LOOPHOLE[message + SIZE[LibjectMessage]];
message.nextfree ← LOOPHOLE[SIZE[LibjectMessage] + 2*SIZE[PropertyPair]];
BEGIN
COPY: PROCEDURE [from: POINTER, nwords: CARDINAL, to: LONG POINTER] =
BEGIN
FOR i: CARDINAL IN [0..nwords) DO (to + i)↑ ← (from + i)↑; ENDLOOP;
END;
string: STRING = "HostWatcher"L;
wordsforstring: CARDINAL = String.WordsForString[string.length];
dataArea: LONG POINTER ← message + LOOPHOLE[message.nextfree, CARDINAL];
plist[0] ← PropertyPair[
empty: FALSE, pn: StringName,
body: String[
length: string.length, string: LOOPHOLE[2*SIZE[PropertyPair]]]];
COPY[from: string, nwords: wordsforstring, to: dataArea];
message.nextfree ← message.nextfree + wordsforstring;
END;
plist[1] ← PropertyPair[empty: TRUE, pn: IDName, body: TwoWord[[lc[0]]]];
SetPupContentsWords[b, LOOPHOLE[message.nextfree, INTEGER]];
soc.put[b];
UNTIL (b ← soc.get[]) = NIL DO
message ← LOOPHOLE[@b.pup.pupWords];
SELECT TRUE FROM
(b.pup.pupType = error AND b.pup.errorCode = noProcessPupErrorCode) =>
BEGIN
i: CARDINAL;
FOR i IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.pup.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pup.pupType = error) => HostWatcherOps.ShowErrorPup[b];
message.password = ValidLibrarianMessage AND message.id = transactionID
=> GOTO Up;
ENDCASE => NULL; -- I wonder what this is
Buffer.ReturnBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN Buffer.ReturnBuffer[b];
PupSocketDestroy[soc];
Buffer.DestroyPool[pool];
END;
PokeSpruce: PUBLIC PROCEDURE [info: Info] =
BEGIN
pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 10];
soc: PupSocket ← PupSocketMake[fillInSocketID, info.address, SecondsToTocks[5]];
spruceStatusRequest: PupType = LOOPHOLE[200B];
spruceStatusReply: PupType = LOOPHOLE[201B];
b: PupBuffer ← NIL;
packetNumber: CARDINAL ← NextSequenceNumber[];
THROUGH [0..20) DO
b ← Buffer.GetBuffer[pup, pool, send];
b.pup.pupID.a ← b.pup.pupID.b ← packetNumber;
b.pup.pupType ← spruceStatusRequest;
SetPupContentsWords[b, 0];
soc.put[b];
UNTIL (b ← soc.get[]) = NIL DO
SELECT TRUE FROM
(b.pup.pupType = error AND b.pup.errorCode = noProcessPupErrorCode) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.pup.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pup.pupType = error) => HostWatcherOps.ShowErrorPup[b];
((b.pup.pupType # spruceStatusReply) OR (b.pup.pupID.a # packetNumber)
OR (b.pup.pupID.b # packetNumber)) => NULL;
ENDCASE =>
BEGIN
FOR i: CARDINAL IN [2..GetPupContentsBytes[b] - 1) DO
c: CHARACTER ← b.pup.pupChars[i];
IF c = Ascii.CR THEN c ← Ascii.SP;
String.AppendChar[info.text, c];
ENDLOOP;
SELECT b.pup.pupWords[0] FROM
1 => GOTO Down; -- Not Spooling
2 => GOTO Up; -- Spooler is idle
3 => GOTO Up; -- Spooler is busy
ENDCASE => NULL;
GOTO Up;
END;
Buffer.ReturnBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Down => info.state ← down;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN Buffer.ReturnBuffer[b];
PupSocketDestroy[soc];
Buffer.DestroyPool[pool];
END;
PokeEftp: PUBLIC PROCEDURE [info: Info] =
BEGIN
pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 2];
soc: PupSocket ← PupSocketMake[fillInSocketID, info.address, SecondsToTocks[5]];
b: PupBuffer ← NIL;
THROUGH [0..20) DO
b ← Buffer.GetBuffer[pup, pool, send];
b.pup.pupID.a ← b.pup.pupID.b ← 0;
b.pup.pupType ← eData;
SetPupContentsWords[b, 0];
soc.put[b];
UNTIL (b ← soc.get[]) = NIL DO
SELECT TRUE FROM
(b.pup.pupType = eAbort) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2) DO
String.AppendChar[info.text, b.pup.pupChars[i + 2]]; ENDLOOP;
GOTO Rejecting;
END;
(b.pup.pupType = error AND b.pup.errorCode = noProcessPupErrorCode) =>
BEGIN
FOR i: CARDINAL IN [0..GetPupContentsBytes[b] - 2*(10 + 1 + 1)) DO
String.AppendChar[info.text, b.pup.errorText[i]]; ENDLOOP;
HostWatcherOps.ShowErrorPup[b];
GOTO Rejecting;
END;
(b.pup.pupType = error) => HostWatcherOps.ShowErrorPup[b];
((b.pup.pupType = eAck) AND (b.pup.pupID.a = 0) AND (b.pup.pupID.b = 0)) => GOTO Up;
ENDCASE => HostWatcherOps.ShowErrorPup[b];
Buffer.ReturnBuffer[b];
b ← NIL;
ENDLOOP;
REPEAT
Rejecting => info.state ← rejecting;
Up => info.state ← up;
FINISHED => info.state ← timeout;
ENDLOOP;
IF b # NIL THEN Buffer.ReturnBuffer[b];
PupSocketDestroy[soc];
Buffer.DestroyPool[pool];
END;
PokePopCorn: PUBLIC PROCEDURE [info: Info] =
BEGIN
msDiff: LONG INTEGER;
msDelay: LONG CARDINAL;
info.state ← up;
[msDiff: msDiff, msDelay: msDelay] ← PopCorn.GetClockOffset[info.address, 2 !
PopCorn.Error =>
BEGIN
String.AppendString[info.text, text];
SELECT why FROM
timeout => info.state ← timeout;
rejecting =>
BEGIN
info.state ← rejecting;
IF CheckForFull[text] THEN info.state ← full;
END;
ENDCASE => info.state ← down;
CONTINUE;
END];
IF info.state = up THEN
BEGIN
String.AppendString[info.text, info.name];
String.AppendString[info.text, "'s time is "L];
String.AppendLongDecimal[info.text, msDiff];
String.AppendString[info.text, " ms faster than ours"L];
String.AppendString[info.text, ", delay was "L];
String.AppendLongDecimal[info.text, msDelay];
String.AppendString[info.text, " ms"L];
END;
END;
sequenceNumber: CARDINAL ← 0;
NextSequenceNumber: PROCEDURE RETURNS [CARDINAL] =
BEGIN RETURN[sequenceNumber ← sequenceNumber + 1]; END;
END.