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