-- 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.