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