-- Copyright (C) 1984 by Xerox Corporation. All rights reserved. -- PupDirServerNoDisk.mesa, HGM, 9-May-86 16:14:21 -- We don't have a copy of the file, but we keep a BIG cache of things we find -- on other servers so we can pass the service on to clients on adjacent nets. -- This module watches the directory version on the net, and flushes the cache -- so it will get reloaded with current information. -- It also "forwards" netDirVersion requests aka the Pup boot servers to keep IFSs happy. DIRECTORY Ascii USING [CR], CmFile USING [Handle, TableError], Heap USING [systemZone], Process USING [Detach, SetTimeout, MsecToTicks], Put USING [Text], String USING [AppendChar, AppendNumber, AppendString, AppendDecimal], StringLookUp USING [noMatch], Time USING [AppendCurrent], Token USING [FreeTokenString, Item, Octal], Buffer USING [AccessHandle, DestroyPool, GetBuffer, MakePool, ReturnBuffer], Indirect USING [Close, NextValue, OpenSection], MiscServerDefs USING [PupMiscServerOn, SetDirectoryServer], NameServerDefs USING [ lockDirRequest, lockDirReply, unlockDirRequest, unlockDirReply, FlushWholeCache, PupNameServerOn, BumpCacheSize], PupDefs USING [ AppendHostName, GetPupAddress, GetPupContentsBytes, PupBuffer, PupNameTrouble, PupRouterBroadcastThis, PupRouterSendThis, PupSocket, PupSocketDestroy, PupSocketID, PupSocketMake, SecondsToTocks, SetPupContentsWords, ReturnPup, UniqueLocalPupSocketID], PupRouterDefs USING [NetworkContext], PupTypes USING [fillInPupAddress, miscSrvSoc, PupAddress, PupNetID], Stats USING [StatCounterIndex, StatIncr]; PupDirServerNoDisk: MONITOR IMPORTS CmFile, Heap, Process, Put, String, Time, Token, Buffer, Indirect, MiscServerDefs, NameServerDefs, PupDefs, Stats EXPORTS NameServerDefs = BEGIN OPEN Stats, NameServerDefs, PupDefs; z: UNCOUNTED ZONE = Heap.systemZone; remote: Chain ← NIL; Chain: TYPE = LONG POINTER TO ChainSlot; ChainSlot: TYPE = RECORD [ next: Chain, source: PupTypes.PupNetID, dest: PupTypes.PupAddress, target: LONG STRING]; dirRunning, probing, sending: PUBLIC BOOLEAN ← FALSE; useCount: CARDINAL ← 0; pleaseStop: BOOLEAN ← FALSE; probePeriod: CARDINAL ← 60; -- in minutes tries: CARDINAL ← 0; delay: CONDITION; lock: BOOLEAN ← FALSE; verbose: BOOLEAN = TRUE; currentVersion: CARDINAL ← 0; oldVersionAround: BOOLEAN ← TRUE; fileName: STRING = "Pup-network.directory"; statVers, statSend: PUBLIC StatCounterIndex; GetNewDirectoryVersion, GetOldDirectoryVersion: PUBLIC PROCEDURE RETURNS [CARDINAL, BOOLEAN] = BEGIN RETURN[currentVersion, FALSE]; END; PupDirServerOn: PUBLIC PROCEDURE = BEGIN IF (useCount ← useCount + 1) = 1 THEN BEGIN dirRunning ← TRUE; Starter[]; END; END; Starter: PROCEDURE = BEGIN pleaseStop ← FALSE; MiscServerDefs.PupMiscServerOn[]; ScanParameterFile[]; MiscServerDefs.SetDirectoryServer[PupDirServer]; Process.Detach[FORK ProbeGovenor[]]; END; CountTries: ENTRY PROCEDURE = BEGIN tries ← tries + 1; END; KickProber: PUBLIC ENTRY PROCEDURE = BEGIN IF tries > 3 THEN RETURN; StartProbing[]; END; StartProbingForDirectory: PUBLIC ENTRY PROCEDURE = BEGIN StartProbing[]; END; StartProbing: INTERNAL PROCEDURE = BEGIN IF pleaseStop OR probing THEN RETURN; probing ← TRUE; Process.Detach[FORK Probe[]]; END; ProbeGovenor: ENTRY PROCEDURE = BEGIN n: CARDINAL ← 1; -- probe 1 min after startup Process.SetTimeout[@delay, Process.MsecToTicks[60000]]; UNTIL pleaseStop DO WAIT delay; -- one minute IF probing THEN BEGIN n ← probePeriod; LOOP; END; IF (n ← n - 1) = 0 THEN BEGIN tries ← 0; StartProbing[]; WHILE probing DO WAIT delay; ENDLOOP; n ← probePeriod; END; ENDLOOP; END; Probe: PROCEDURE = BEGIN b: PupBuffer; from: PupSocketID ← UniqueLocalPupSocketID[]; pool: Buffer.AccessHandle; soc: PupSocket; bestSoFar: CARDINAL; where: PupTypes.PupAddress; sawOldVersion: BOOLEAN ← FALSE; bestSoFar ← currentVersion; pool ← Buffer.MakePool[send: 1, receive: 10]; soc ← PupSocketMake[from, PupTypes.fillInPupAddress, SecondsToTocks[1]]; THROUGH [0..5) UNTIL bestSoFar > currentVersion DO b ← Buffer.GetBuffer[pup, pool, send]; b.pup.source.socket ← from; b.pup.dest.socket ← PupTypes.miscSrvSoc; b.pup.pupType ← netDirVersion; b.pup.pupWords[0] ← 0; b.pup.pupWords[1] ← 0; SetPupContentsWords[b, 2]; PupRouterBroadcastThis[b]; UNTIL b = NIL DO b ← soc.get[]; IF b # NIL THEN BEGIN IF b.pup.pupType = netDirVersion THEN BEGIN SELECT b.pup.pupWords[0] FROM > bestSoFar => BEGIN bestSoFar ← b.pup.pupWords[0]; where ← b.pup.source; END; < currentVersion => sawOldVersion ← TRUE; ENDCASE => NULL; IF GetPupContentsBytes[b] > 2 THEN BEGIN SELECT b.pup.pupWords[1] FROM > bestSoFar => BEGIN bestSoFar ← b.pup.pupWords[0]; where ← b.pup.source; END; < currentVersion => sawOldVersion ← TRUE; ENDCASE => NULL; END; END; Buffer.ReturnBuffer[b]; END; ENDLOOP; ENDLOOP; PupSocketDestroy[soc]; Buffer.DestroyPool[pool]; IF bestSoFar > currentVersion THEN BEGIN IF verbose THEN BEGIN OPEN String; text: STRING = [100]; Time.AppendCurrent[text]; AppendString[text, " Saw "L]; AppendString[text, fileName]; AppendString[text, "!"L]; AppendDecimal[text, bestSoFar]; AppendString[text, " on "L]; AppendHostName[text, where]; LogString[text]; END; FlushWholeCache[]; currentVersion ← bestSoFar; probing ← FALSE; RETURN; END; IF sawOldVersion OR oldVersionAround THEN BEGIN oldVersionAround ← sawOldVersion; FlushWholeCache[]; END; probing ← FALSE; END; PupDirServer: PUBLIC PROCEDURE [b: PupBuffer] = BEGIN IF ~(lock OR pleaseStop) OR b.pup.pupType = unlockDirRequest THEN SELECT b.pup.pupType FROM netDirVersion => BEGIN StatIncr[statVers]; SELECT b.pup.pupWords[0] FROM = currentVersion => NULL; -- we have the same ones > currentVersion => KickProber[]; -- he has a newer one < currentVersion => NULL; -- Don't respond since we can't send it ENDCASE => ERROR; MaybeForwardThisOne[b]; RETURN; END; sendNetDir => NULL; lockDirRequest => BEGIN lock ← TRUE; ReturnPup[b, lockDirReply, 0]; FlushWholeCache[]; RETURN; END; unlockDirRequest => BEGIN wasLocked: BOOLEAN ← lock; lock ← FALSE; ReturnPup[b, unlockDirReply, 0]; tries ← 0; KickProber[]; RETURN; END; ENDCASE; Buffer.ReturnBuffer[b]; END; MaybeForwardThisOne: PROCEDURE [b: PupDefs.PupBuffer] = BEGIN context: PupRouterDefs.NetworkContext = b.context; IF b.pup.source.net = 0 THEN b.pup.source.net ← [context.pupNetNumber]; FOR finger: Chain ← remote, finger.next UNTIL finger = NIL DO IF context.pupNetNumber = finger.source THEN BEGIN IF finger.dest = PupTypes.fillInPupAddress THEN EXIT; b.pup.dest.net ← finger.dest.net; b.pup.dest.host ← finger.dest.host; PupDefs.PupRouterSendThis[b]; RETURN; END; ENDLOOP; Buffer.ReturnBuffer[b]; END; ScanParameterFile: PROCEDURE = BEGIN cmFile: CmFile.Handle; Option: TYPE = {remote}; NextValue: PROCEDURE [ h: CmFile.Handle, table: LONG DESCRIPTOR FOR ARRAY Option OF LONG STRING] RETURNS [Option] = LOOPHOLE[Indirect.NextValue]; optionTable: ARRAY Option OF LONG STRING ← [remote: "Remote"L]; cmFile ← Indirect.OpenSection["PupDirServer"L]; IF cmFile = NIL THEN RETURN; DO option: Option; option ← NextValue[ cmFile, DESCRIPTOR[optionTable] ! CmFile.TableError => BEGIN IF name[0] # '; THEN Message["Unrecognized parameter: ", name]; RETRY; END]; SELECT option FROM LOOPHOLE[StringLookUp.noMatch] => EXIT; remote => BEGIN source: PupTypes.PupNetID = [Token.Octal[cmFile]]; temp: LONG STRING ← Token.Item[cmFile, FALSE]; new: Chain ← z.NEW[ChainSlot]; new↑ ← [NIL, source, PupTypes.fillInPupAddress, z.NEW[StringBody[temp.length]]]; String.AppendString[new.target, temp]; [] ← Token.FreeTokenString[temp]; PupDefs.GetPupAddress[@new.dest, new.target ! PupDefs.PupNameTrouble => CONTINUE]; IF remote = NIL THEN remote ← new ELSE BEGIN FOR finger: Chain ← remote, finger.next DO IF finger.next = NIL THEN BEGIN finger.next ← new; EXIT; END; ENDLOOP; END; MessageNet["Forwarding Pup NetDirVersion requests from net "L, new.source, " to "L, new.target]; END; ENDCASE => ERROR; ENDLOOP; Indirect.Close[cmFile]; END; MessageNet: PROCEDURE [one: LONG STRING, net: CARDINAL, three, four: LONG STRING] = BEGIN two: STRING = [20]; String.AppendNumber[two, net, 8]; Message[one, two, three, four]; END; Message: PROCEDURE [one, two, three, four: LONG STRING ← NIL] = BEGIN text: STRING = [200]; String.AppendString[text, one]; IF two # NIL THEN String.AppendString[text, two]; IF three # NIL THEN String.AppendString[text, three]; IF four # NIL THEN String.AppendString[text, four]; LogString[text]; END; LogString: PROCEDURE [text: LONG STRING] = BEGIN String.AppendChar[text, '.]; String.AppendChar[text, Ascii.CR]; Put.Text[NIL, text]; END; -- initialization PupDirServerOn[]; NameServerDefs.PupNameServerOn[]; NameServerDefs.BumpCacheSize[2000]; END.