-- File: PupDirServer.mesa, Last Edit: HGM March 8, 1981 1:25 AM DIRECTORY Ascii USING [CR], Process USING [Detach, SetTimeout, MsecToTicks, Pause, Yield], String USING [EquivalentString, AppendChar, AppendString, AppendDecimal], Time USING [AppendCurrent], Event USING [Item, Reason, AddNotifier], Put USING [Line], Window USING [Handle], File USING [Capability], MiscServerDefs USING [ PupMiscServerOn, PupMiscServerOff, IgnoreThisPacket, SetDirectoryServer], Slosh USING [ AddProcs, RecvStatus, RecvFile, RejectThisTrash, RetransmissionInterval, SendFile, Why], NameServerDefs USING [ lockDirRequest, lockDirReply, unlockDirRequest, unlockDirReply, CloseDirectoryFile, CheckDirectoryFile, FlushWholeCache, GetDirectoryFile, GetDirectoryVersion, OpenDirectoryFile, ResetDirectoryFile], StatsDefs USING [StatCounterIndex, StatIncr], PupDefs USING [ GetFreePupBuffer, AppendHostName, PupAddress, PupBuffer, PupRouterBroadcastThis, PupSocket, PupSocketDestroy, PupSocketID, PupSocketMake, ReturnFreePupBuffer, SecondsToTocks, SetPupContentsWords, ReturnPup, SendPup, UniqueLocalPupAddress, UniqueLocalPupSocketID], PupTypes USING [fillInPupAddress, miscSrvSoc]; PupDirServer: MONITOR IMPORTS Process, String, Time, Event, Put, Slosh, MiscServerDefs, NameServerDefs, StatsDefs, PupDefs EXPORTS NameServerDefs = BEGIN OPEN StatsDefs, NameServerDefs, PupDefs; msg: PUBLIC Window.Handle ← NIL; eventItem: Event.Item ← [eventMask: 177777B, eventProc: Broom]; dirRunning, probing, announcing, 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; directoryName: STRING = "Pup-Network.Directory"; statVers, statSend: PUBLIC StatCounterIndex; PupDirServerOn: PUBLIC PROCEDURE = BEGIN IF (useCount ← useCount + 1) = 1 THEN BEGIN dirRunning ← TRUE; Starter[]; END; --UpdatePicture[]; END; Starter: PROCEDURE = BEGIN pleaseStop ← FALSE; MiscServerDefs.PupMiscServerOn[]; OpenDirectoryFile[]; currentVersion ← GetDirectoryVersion[]; MiscServerDefs.SetDirectoryServer[PupDirServer]; Process.Detach[FORK ProbeGovenor[]]; END; PupDirServerOff: PUBLIC PROCEDURE = BEGIN IF useCount # 0 AND (useCount ← useCount - 1) = 0 THEN BEGIN dirRunning ← FALSE; Stopper[]; END; --UpdatePicture[]; END; Stopper: PROCEDURE = BEGIN StopperLocked: ENTRY PROCEDURE = BEGIN NOTIFY delay; END; MiscServerDefs.SetDirectoryServer[MiscServerDefs.IgnoreThisPacket]; pleaseStop ← TRUE; StopperLocked[]; WHILE probing OR announcing OR sending DO Process.Yield[]; ENDLOOP; CloseDirectoryFile[]; MiscServerDefs.PupMiscServerOff[]; END; CountTries: ENTRY PROCEDURE = BEGIN tries ← tries + 1; END; KickProber: 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 (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[]; socket: PupSocket; bestSoFar: CARDINAL ← currentVersion; where: PupAddress; socket ← PupSocketMake[from, PupTypes.fillInPupAddress, SecondsToTocks[1]]; THROUGH [0..5) UNTIL bestSoFar > currentVersion DO b ← GetFreePupBuffer[]; b.source.socket ← from; b.dest.socket ← PupTypes.miscSrvSoc; b.pupType ← netDirVersion; b.pupWords[0] ← currentVersion; SetPupContentsWords[b, 1]; PupRouterBroadcastThis[b]; UNTIL b = NIL DO b ← socket.get[]; IF b # NIL THEN BEGIN IF b.pupType = netDirVersion AND b.pupWords[0] > bestSoFar THEN BEGIN bestSoFar ← b.pupWords[0]; where ← b.source; END; ReturnFreePupBuffer[b]; END; ENDLOOP; ENDLOOP; PupSocketDestroy[socket]; IF bestSoFar > currentVersion THEN BEGIN IF verbose THEN BEGIN OPEN String; text: STRING = [100]; Time.AppendCurrent[text]; AppendString[text, " Found Pup-Network.Directory!"L]; AppendDecimal[text, bestSoFar]; AppendString[text, " on "L]; AppendHostName[text, where]; AppendChar[text, '.]; LogString[text]; END; Process.Detach[FORK GetNewDirectory[where]]; RETURN; END; probing ← FALSE; END; Announce: PROCEDURE = BEGIN b: PupBuffer; THROUGH [0..5) UNTIL pleaseStop DO Process.Pause[1000]; b ← GetFreePupBuffer[]; b.source.socket ← b.dest.socket ← PupTypes.miscSrvSoc; b.pupType ← netDirVersion; b.pupWords[0] ← currentVersion; SetPupContentsWords[b, 1]; PupRouterBroadcastThis[b]; ENDLOOP; announcing ← FALSE; END; GetNewDirectory: PROCEDURE [where: PupAddress] = BEGIN from: PupAddress ← UniqueLocalPupAddress[@where]; status: Slosh.RecvStatus; Ask: PROCEDURE = BEGIN b: PupBuffer ← GetFreePupBuffer[]; b.source ← from; b.dest ← where; b.address ← from; SendPup[b, sendNetDir, 2*SIZE[PupAddress]]; END; CountTries[]; status ← Slosh.RecvFile[ msg, directoryName, "Pup-Network.scratch$"L, GetDirectoryFile[], from, Ask]; IF status # statusStoreOk THEN BEGIN n: CARDINAL ← Slosh.RetransmissionInterval[]; IF status = statusDiskFull THEN { CountTries[]; CountTries[]; CountTries[]; }; THROUGH [0..n) UNTIL pleaseStop DO Process.Pause[Process.MsecToTicks[1000]]; ENDLOOP; END; probing ← FALSE; IF status # statusStoreOk THEN KickProber[]; END; Checker: PROCEDURE [why: Slosh.Why, fileName: STRING, temp: File.Capability] = BEGIN IF ~String.EquivalentString[fileName, directoryName] THEN RETURN; SELECT why FROM check => IF ~CheckDirectoryFile[temp] THEN ERROR Slosh.RejectThisTrash[NIL]; release => CloseDirectoryFile[]; arrived, failed => BEGIN currentVersion ← ResetDirectoryFile[]; FlushWholeCache[]; announcing ← TRUE; Process.Detach[FORK Announce[]]; END; ENDCASE => ERROR END; SendDirectory: ENTRY PROCEDURE [where: PupAddress] = BEGIN IF verbose THEN BEGIN text: STRING = [100]; Time.AppendCurrent[text]; String.AppendString[text, " Pup-Network.Directory wanted by "L]; AppendHostName[text, where]; String.AppendChar[text, '.]; LogString[text]; END; IF Slosh.SendFile[msg, directoryName, GetDirectoryFile[], where] = ok THEN StatIncr[statSend]; sending ← FALSE; END; PupDirServer: PUBLIC PROCEDURE [b: PupBuffer] = BEGIN IF ~(lock OR pleaseStop) OR b.pupType = unlockDirRequest THEN SELECT b.pupType FROM netDirVersion => BEGIN StatIncr[statVers]; SELECT b.pupWords[0] FROM = currentVersion => NULL; -- we have the same ones > currentVersion => KickProber[]; -- he has a newer one < currentVersion => -- tell him about our newer one BEGIN b.pupWords[0] ← currentVersion; ReturnPup[b, netDirVersion, 2]; RETURN; END; ENDCASE => ERROR; END; sendNetDir => BEGIN IF ~sending THEN BEGIN sending ← TRUE; Process.Detach[FORK SendDirectory[b.address]]; END; END; lockDirRequest => BEGIN lock ← TRUE; ReturnPup[b, lockDirReply, 0]; CloseDirectoryFile[]; FlushWholeCache[]; currentVersion ← 0; RETURN; END; unlockDirRequest => BEGIN lock ← FALSE; ReturnPup[b, unlockDirReply, 0]; IF currentVersion = 0 THEN currentVersion ← ResetDirectoryFile[]; tries ← 0; KickProber[]; RETURN; END; ENDCASE; ReturnFreePupBuffer[b]; END; LogString: PROCEDURE [text: STRING] = BEGIN IF msg # NIL THEN Put.Line[msg, text]; Put.Line[NIL, text]; END; Broom: PROCEDURE [why: Event.Reason] = BEGIN IF useCount = 0 THEN RETURN; SELECT why FROM makeImage, makeCheck, stopMesa => IF dirRunning THEN Stopper[]; startImage, restartCheck, continueCheck => IF dirRunning THEN Starter[]; ENDCASE => NULL; END; -- initialization Event.AddNotifier[@eventItem]; Slosh.AddProcs[Checker]; END.