-- Copyright (C) 1983 by Xerox Corporation. All rights reserved. -- PupBootServerCold.mesa, HGM, 24-Sep-83 15:56:30 DIRECTORY Ascii USING [CR], Process USING [Detach, SetTimeout, MsecToTicks, Pause, Yield], Put USING [Text], Runtime USING [IsBound], Stream USING [Handle], String USING [AppendChar, AppendString, Equivalent], System USING [GreenwichMeanTime, GetGreenwichMeanTime], Time USING [AppendCurrent], Window USING [Handle], Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], Driver USING [Network], BootServer USING [AppendBFN, CardinalToPupBFN, PupBFNToCardinal], BootServerDefs USING [ SendBootDir, BreatherOn, BreatherOff, PupBootServer, UpdatePicture, BootStatsEntry, bootStatsReply, bootVersion], BootServerFriends USING [ BootFile, BootFileNumber, CreateTempFile, DeleteTempFile, FileHandle, GetPointerToBootTable, MakeTempFileIntoBootFile, timeNotKnown], MiscServerDefs USING [ PupMiscServerOn, PupMiscServerOff, IgnoreThisPacket, SetBootServer], PupDefs USING [ AppendHostName, PupAddress, PupBuffer, SendPup, PupSocket, PupSocketDestroy, PupSocketID, PupSocketMake, SecondsToTocks, SetPupContentsWords, GetPupContentsBytes, UniqueLocalPupSocketID, UniqueLocalPupAddress, ReturnPup, defaultNumberOfNetworks, GetHopsToNetwork], PupTypes USING [miscSrvSoc, PupNetID, allNets, allHosts], PupWireFormat USING [ BcplLongNumber, BcplToMesaLongNumber, BcplSTRING, MesaToBcplLongNumber], Slosh USING [RecvFile, RecvStatus, RetransmissionInterval], Stats USING [StatCounterIndex, StatGetCounter]; PupBootServerCold: MONITOR LOCKS lock IMPORTS Process, Put, Runtime, String, System, Time, BootServer, BootServerDefs, BootServerFriends, Buffer, MiscServerDefs, PupDefs, PupWireFormat, Slosh, Stats EXPORTS Buffer, BootServerDefs SHARES Buffer = BEGIN OPEN BootServerDefs; -- EXPORTed TYPEs Network: PUBLIC TYPE = Driver.Network; lock: PUBLIC MONITORLOCK; running, booting, slowBooting, pleaseStop, probing, sloshing: PUBLIC BOOLEAN ← FALSE; longRangeMode: BOOLEAN ← FALSE; msg: PUBLIC Window.Handle ← NIL; slosheeHost, slosheeFileName: PUBLIC LONG STRING ← NIL; first: LONG POINTER TO BootServerFriends.BootFile ← BootServerFriends.GetPointerToBootTable[]; probeTicks: CARDINAL ← 1*3600/5; -- 1 hour statLife: PUBLIC Stats.StatCounterIndex; statBootNew: PUBLIC Stats.StatCounterIndex; statBootDir: PUBLIC Stats.StatCounterIndex; statFile: PUBLIC Stats.StatCounterIndex; statSun: PUBLIC Stats.StatCounterIndex; statFileSent: PUBLIC Stats.StatCounterIndex; statFileSentSlow: PUBLIC Stats.StatCounterIndex; statFileTroubles: PUBLIC Stats.StatCounterIndex; statFileNeverStarted: PUBLIC Stats.StatCounterIndex; statBusyDisk: PUBLIC Stats.StatCounterIndex; statBusyBooting: PUBLIC Stats.StatCounterIndex; statMicrocodeBooted: PUBLIC Stats.StatCounterIndex; statUnknown: PUBLIC Stats.StatCounterIndex; verbose: BOOLEAN = TRUE; PupBootServerOn: PUBLIC PROCEDURE = BEGIN running ← TRUE; pleaseStop ← FALSE; MiscServerDefs.PupMiscServerOn[]; MiscServerDefs.SetBootServer[BootServerDefs.PupBootServer]; Process.Detach[FORK BootServerDefs.BreatherOn[]]; Process.Detach[FORK Prober[]]; FixupPicture[]; END; PupBootServerOff: PUBLIC PROCEDURE = BEGIN running ← FALSE; pleaseStop ← TRUE; MiscServerDefs.SetBootServer[MiscServerDefs.IgnoreThisPacket]; BreatherOff[]; WHILE booting OR slowBooting OR probing OR sloshing DO Process.Pause[Process.MsecToTicks[100]]; ENDLOOP; MiscServerDefs.PupMiscServerOff[]; FixupPicture[]; END; FixupPicture: PROCEDURE = BEGIN IF msg # NIL AND Runtime.IsBound[LOOPHOLE[UpdatePicture]] THEN UpdatePicture[]; END; Newer: PROCEDURE [him, me: System.GreenwichMeanTime] RETURNS [BOOLEAN] = BEGIN IF him = BootServerFriends.timeNotKnown THEN RETURN[FALSE]; RETURN[him > me]; -- FIX THIS FOR EPOC STUFF END; -- This stuff should probably migrate to another file StartProbingForBootFiles: PUBLIC ENTRY PROCEDURE = BEGIN longRangeMode ← FALSE; ProbeForBootFiles[]; END; StartLongRangeProbingForBootFiles: PUBLIC ENTRY PROCEDURE = BEGIN longRangeMode ← TRUE; ProbeForBootFiles[]; END; Prober: ENTRY PROCEDURE = BEGIN counter: CARDINAL ← 120/5; -- initial probe 2 min after startup delay: CONDITION; tryHarder: CARDINAL ← 0; Process.SetTimeout[@delay, Process.MsecToTicks[5000]]; UNTIL pleaseStop DO WAIT delay; IF (counter ← counter - 1) = 0 THEN BEGIN tryHarder ← tryHarder + 1; longRangeMode ← (tryHarder MOD 24) = 0; ProbeForBootFiles[]; counter ← probeTicks; END; ENDLOOP; END; ProbeForBootFiles: INTERNAL PROCEDURE = BEGIN IF probing OR sloshing THEN RETURN; probing ← TRUE; FOR bf: BootServerFriends.BootFile ← first↑, bf.next UNTIL bf = NIL DO bf.tries ← 0; ENDLOOP; IF longRangeMode THEN Process.Detach[FORK LongRangeProbe[]] ELSE Process.Detach[FORK ShortRangeProbe[]]; END; ProbeSomeMore: ENTRY PROCEDURE = BEGIN IF probing OR sloshing THEN RETURN; probing ← TRUE; IF longRangeMode THEN Process.Detach[FORK LongRangeProbe[]] ELSE Process.Detach[FORK ShortRangeProbe[]]; END; ShortRangeProbe: PROCEDURE = BEGIN OPEN PupDefs; FixupPicture[]; ProbeOne[PupTypes.allNets]; probing ← FALSE; FixupPicture[]; IF ~sloshing THEN BootServerDefs.SendBootDir[NIL]; END; LongRangeProbe: PROCEDURE = BEGIN FixupPicture[]; FOR net: CARDINAL IN [1..PupDefs.defaultNumberOfNetworks) DO IF PupDefs.GetHopsToNetwork[[net]] > 3 THEN LOOP; ProbeOne[[net]]; IF sloshing THEN EXIT; ENDLOOP; probing ← FALSE; FixupPicture[]; IF ~sloshing THEN BootServerDefs.SendBootDir[NIL]; END; ProbeOne: PROCEDURE [net: PupTypes.PupNetID] = BEGIN OPEN PupDefs; pool: Buffer.AccessHandle ← Buffer.MakePool[send: 1, receive: 10]; soc: PupSocket ← PupSocketMake[ UniqueLocalPupSocketID[], [net, PupTypes.allHosts, PupTypes.miscSrvSoc], SecondsToTocks[2]]; b: PupBuffer; THROUGH [0..5) UNTIL pleaseStop OR sloshing DO b ← Buffer.GetBuffer[pup, pool, send]; b.pup.pupType ← bootDirReq; SetPupContentsWords[b, 0]; soc.put[b]; UNTIL pleaseStop OR sloshing DO b ← soc.get[]; IF b = NIL THEN EXIT; IF b.pup.pupType # bootDirReply THEN BEGIN Buffer.ReturnBuffer[b]; LOOP; END; LookAtBootDir[b]; ENDLOOP; ENDLOOP; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; END; LookAtBootDir: PUBLIC ENTRY PROCEDURE [b: PupDefs.PupBuffer] = BEGIN OPEN PupDefs; bf: BootServerFriends.BootFile ← NIL; where: PupAddress ← b.pup.source; name: STRING = [256]; word, size, end: CARDINAL; timeStamp: System.GreenwichMeanTime; timeStampLocation: LONG POINTER TO PupWireFormat.BcplLongNumber; now: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[]; heNeedsOne: BOOLEAN ← FALSE; IF pleaseStop THEN GOTO Stopping; IF sloshing THEN GOTO AlreadySloshing; BEGIN network: Network ← b.network; IF network.pupNetNumber = b.pup.source.net AND network.pupHostNumber = b.pup.source.host THEN GOTO FromMe; END; end ← GetPupContentsBytes[b]/2; word ← 0; UNTIL word >= end OR bf # NIL DO timeStampLocation ← LOOPHOLE[@b.pup.pupWords[word + 1]]; timeStamp ← LOOPHOLE[PupWireFormat.BcplToMesaLongNumber[ timeStampLocation↑]]; StringCopy[LOOPHOLE[@b.pup.pupWords[word + 1 + 2]], name]; size ← ((1 + name.length) + 1)/2; FOR bf ← first↑, bf.next UNTIL bf = NIL DO IF ~bf.pup THEN LOOP; IF b.pup.pupWords[word] >= 100000B THEN LOOP; IF bf.inTransit THEN LOOP; IF bf.code # BootServer.CardinalToPupBFN[b.pup.pupWords[word]] THEN LOOP; IF ~String.Equivalent[name, bf.fileName] THEN LOOP; IF Newer[timeStamp, now] THEN LOOP; -- Don't propagate garbage IF ~bf.unknown AND bf.create # BootServerFriends.timeNotKnown AND Newer[bf.create, timeStamp] THEN heNeedsOne ← TRUE; IF ~bf.unknown AND ~Newer[timeStamp, bf.create] THEN LOOP; IF bf.tries > 1 THEN LOOP; EXIT; ENDLOOP; word ← word + size + 1 + 2; ENDLOOP; IF sloshing THEN GOTO Sloshing; -- This is just a hack to let him get the new version sooner. It should all work ok without this code. IF heNeedsOne THEN BEGIN b.pup.dest.socket ← PupTypes.miscSrvSoc; BootServerDefs.SendBootDir[b]; END ELSE Buffer.ReturnBuffer[b]; -- Don't call AppendHostName (or friends) from here. The lock is still locked. IF bf # NIL THEN BEGIN sloshing ← TRUE; bf.tries ← bf.tries + 1; Process.Detach[FORK GetNewBootFile[bf, where]]; RETURN; END; EXITS AlreadySloshing, FromMe, Stopping, Sloshing => Buffer.ReturnBuffer[b]; END; StringCopy: PROCEDURE [ s: LONG POINTER TO PupWireFormat.BcplSTRING, d: LONG STRING] = BEGIN d.length ← s.length; FOR i: CARDINAL IN [0..s.length) DO d[i] ← s.char[i]; ENDLOOP; END; GetNewBootFile: PROCEDURE [ bf: BootServerFriends.BootFile, where: PupDefs.PupAddress] = BEGIN OPEN PupDefs; pool: Buffer.AccessHandle; hisName: STRING = [30]; from: PupAddress ← UniqueLocalPupAddress[@where]; fh: BootServerFriends.FileHandle; sh: Stream.Handle; status: Slosh.RecvStatus; Ask: PROCEDURE = BEGIN b: PupBuffer ← Buffer.GetBuffer[pup, pool, send]; b.pup.source ← from; b.pup.dest ← where; b.pup.pupID ← [0, BootServer.PupBFNToCardinal[bf.code]]; SendPup[b, bootFileSend, 0]; END; AppendHostName[hisName, where]; slosheeHost ← hisName; slosheeFileName ← bf.fileName; FixupPicture[]; IF verbose THEN StartupMessage[bf, where]; DoSomeYields[]; [fh, sh] ← BootServerFriends.CreateTempFile[]; IF fh = NIL THEN BEGIN Message["Rats, disk full or something (can't get temp file)."L]; sloshing ← FALSE; slosheeHost ← slosheeFileName ← NIL; FixupPicture[]; RETURN; END; pool ← Buffer.MakePool[send: 1, receive: 0]; status ← Slosh.RecvFile[msg, bf.fileName, sh, from, Ask]; Buffer.DestroyPool[pool]; IF status = statusStoreOk THEN BEGIN IF bf.unknown THEN bf.inTransit ← TRUE; IF ~BootServerFriends.MakeTempFileIntoBootFile[bf, fh] THEN Message["Oops, after all that, it didn't quite work."L]; END ELSE BEGIN n: CARDINAL ← Slosh.RetransmissionInterval[]; BootServerFriends.DeleteTempFile[fh]; IF status = statusDiskFull THEN bf.tries ← bf.tries + 1; THROUGH [0..n) UNTIL pleaseStop DO Process.Pause[Process.MsecToTicks[1000]]; ENDLOOP; END; sloshing ← FALSE; slosheeHost ← slosheeFileName ← NIL; FixupPicture[]; IF pleaseStop OR probing THEN RETURN; DoSomeYields[]; ProbeSomeMore[]; END; StartupMessage: PROCEDURE [ bf: BootServerFriends.BootFile, where: PupDefs.PupAddress] = BEGIN text: STRING = [100]; Time.AppendCurrent[text]; String.AppendString[text, " Found "L]; IF ~bf.unknown THEN String.AppendString[text, "newer version of "L]; String.AppendString[text, bf.fileName]; String.AppendString[text, " (#"L]; BootServer.AppendBFN[text, bf.code]; String.AppendString[text, ") on "L]; PupDefs.AppendHostName[text, where]; LogString[text]; END; BootServerStats: PUBLIC PROCEDURE [b: PupDefs.PupBuffer] = BEGIN OPEN Stats; WireCounter: PROCEDURE [s: StatCounterIndex] RETURNS [PupWireFormat.BcplLongNumber] = BEGIN RETURN[PupWireFormat.MesaToBcplLongNumber[StatGetCounter[s]]]; END; bse: LONG POINTER TO BootStatsEntry ← LOOPHOLE[@b.pup.pupWords]; bse↑ ← [ version: bootVersion, directories: WireCounter[statBootDir], fastSends: WireCounter[statFileSent], slowSends: WireCounter[statFileSentSlow], filesRecv: WireCounter[statBootNew]]; PupDefs.ReturnPup[b, bootStatsReply, 2*SIZE[BootStatsEntry]]; END; Message: PROCEDURE [s1, s2, s3, s4: LONG STRING ← NIL] = BEGIN text: STRING = [200]; String.AppendString[text, "BootServer: "L]; String.AppendString[text, s1]; IF s2 # NIL THEN String.AppendString[text, s2]; IF s3 # NIL THEN String.AppendString[text, s3]; IF s4 # NIL THEN String.AppendString[text, s4]; LogString[text]; END; LogString: PROCEDURE [text: LONG STRING] = BEGIN String.AppendChar[text, '.]; String.AppendChar[text, Ascii.CR]; Put.Text[NIL, text]; IF msg # NIL THEN Put.Text[msg, text]; END; DoSomeYields: PROCEDURE = BEGIN THROUGH [0..100) DO Process.Yield[]; ENDLOOP; END; -- initialization END.