DIRECTORY BasicTime USING [FromPupTime, GMT, Now, nullGMT, Period], FSBackdoor USING [Version], FSRemoteFile USING [GetServerPupName, LookupResult], PrincOps USING [zEXCH], Process USING [Detach, Ticks, SecondsToTicks], PupDefs USING [GetFreePupBuffer, GetHopsToNetwork, GetPupAddress, MsToTocks, PupAddress, PupNameTrouble, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, ReturnFreePupBuffer, SetPupContentsBytes], PupTypes USING [fillInSocketID, Pair, PupSocketID, PupType], Rope USING [Equal, Fetch, Length, ROPE], RuntimeError USING [UNCAUGHT]; FSFileLookupImpl: CEDAR MONITOR IMPORTS BasicTime, FSRemoteFile, Process, PupDefs, Rope, RuntimeError EXPORTS FSRemoteFile = { CARD: TYPE = LONG CARDINAL; GMT: TYPE = BasicTime.GMT; ROPE: TYPE = Rope.ROPE; Lookup: PUBLIC PROC [server, file: ROPE] RETURNS [result: FSRemoteFile.LookupResult, version: FSBackdoor.Version, create: GMT, count: INT] = { sI: REF ServerInfo; [result, sI] _ FindServer[server]; IF result = ok THEN { [result, version, create, count] _ DoFileLookup[sI.addr, file]; SetState[sI, result]; }; }; serverList: REF ServerInfo _ NIL; -- list of known servers; keepingList: BOOL _ TRUE; packetCount: CARD _ 0; -- outgoing; also used as pupID ReverseCardinal: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL]; ServerInfo: TYPE = RECORD [ name: ROPE, addr: PupDefs.PupAddress, state: FSRemoteFile.LookupResult, -- can be noResponse, noSuchPort, or ok timeOK: GMT, -- GMT of last ok timeErr: GMT, -- GMT of last error next: REF ServerInfo]; FindServer: ENTRY PROC [server: ROPE] RETURNS [result: FSRemoteFile.LookupResult, info: REF ServerInfo] = TRUSTED { ENABLE UNWIND => NULL; result _ ok; FOR info _ serverList, info.next UNTIL info = NIL DO IF Rope.Equal[info.name, server, FALSE] THEN {result _ info.state; RETURN}; ENDLOOP; { LookupFileSocket: PupTypes.PupSocketID = [0, 61B]; addr: PupDefs.PupAddress; addr _ PupDefs.GetPupAddress[LookupFileSocket, FSRemoteFile.GetServerPupName[server] ! PupDefs.PupNameTrouble => { SELECT code FROM errorFromServer => result _ noSuchServer; ENDCASE => result _ noResponse; CONTINUE } ]; IF result # noSuchServer THEN { time: GMT _ BasicTime.Now[]; info _ NEW [ServerInfo _ [ name: server, addr: addr, state: result, timeOK: IF result = ok THEN time ELSE BasicTime.nullGMT, timeErr: IF result # ok THEN time ELSE BasicTime.nullGMT, next: serverList]]; IF serverList = NIL THEN Process.Detach[FORK ServerCollector[]]; IF keepingList THEN serverList _ info; }; }; }; DoFileLookup: PROC [addr: PupDefs.PupAddress, file: ROPE] RETURNS [result: FSRemoteFile.LookupResult, version: FSBackdoor.Version, create: GMT, count: INT] = TRUSTED { LookupFileType: PupTypes.PupType = LOOPHOLE[200B]; LookupFileReplyType: PupTypes.PupType = LOOPHOLE[201B]; LookupFileErrorType: PupTypes.PupType = LOOPHOLE[202B]; tries: CARDINAL = 4; msWait: CARDINAL = 2000+500*MIN[8, PupDefs.GetHopsToNetwork[addr.net]]; s: PupDefs.PupSocket; fileNameChars: CARDINAL = Rope.Length[file]; result _ noResponse; -- assume result s _ PupDefs.PupSocketMake [local: PupTypes.fillInSocketID, remote: addr, ticks: PupDefs.MsToTocks[msWait] ]; THROUGH [1..tries] DO b: PupDefs.PupBuffer = PupDefs.GetFreePupBuffer[]; b.pupType _ LookupFileType; b.pupID _ PupIDFromLongCardinal[packetCount _ packetCount + 1]; FOR i: CARDINAL IN [0 .. fileNameChars) DO b.pupChars[i] _ Rope.Fetch[file, i]; ENDLOOP; PupDefs.SetPupContentsBytes[b, fileNameChars]; s.put[b]; { r: PupDefs.PupBuffer = s.get[]; IF r = NIL THEN LOOP; -- no response yet SELECT r.pupType FROM LookupFileReplyType => { rPtr: LONG POINTER TO MACHINE DEPENDENT RECORD[v: CARDINAL, c, l: ReverseCardinal] = LOOPHOLE[@r.pupBody]; result _ ok; version _ [rPtr.v]; create _ BasicTime.FromPupTime[ LongCardFromReverseCardinal[rPtr.c] ! RuntimeError.UNCAUGHT => {create _ BasicTime.nullGMT; CONTINUE}]; count _ LongCardFromReverseCardinal[rPtr.l]; }; LookupFileErrorType => result _ noSuchFile; error => SELECT r.errorCode FROM noProcessPupErrorCode => result _ noSuchPort; cantGetTherePupErrorCode => NULL; ENDCASE => {PupDefs.ReturnFreePupBuffer[r]; LOOP}; ENDCASE => {PupDefs.ReturnFreePupBuffer[r]; LOOP}; PupDefs.ReturnFreePupBuffer[r]; EXIT; }; ENDLOOP; PupDefs.PupSocketDestroy[s]; }; PupIDFromLongCardinal: PROC [s: CARD] RETURNS [PupTypes.Pair] = TRUSTED MACHINE CODE {PrincOps.zEXCH}; LongCardFromReverseCardinal: PROC [r: ReverseCardinal] RETURNS [CARD] = TRUSTED MACHINE CODE {PrincOps.zEXCH}; SetState: ENTRY PROC [info: REF ServerInfo, state: FSRemoteFile.LookupResult] = { ENABLE UNWIND => NULL; time: GMT _ BasicTime.Now[]; IF state = ok THEN info.timeOK _ time ELSE info.timeErr _ time; SELECT state FROM noResponse, noSuchPort => info.state _ state; ENDCASE; }; pollingInterval: NAT _ 5; okTimeout: NAT _ 1800; noResponseTimeout: NAT _ 30; noSuchPortTimeout: NAT _ 30; errorTimeout: NAT _ 30; ServerCollector: ENTRY PROC = { ENABLE UNWIND => NULL; UNTIL serverList = NIL DO last: REF ServerInfo _ NIL; forPolling: CONDITION _ [Process.SecondsToTicks[pollingInterval]]; WAIT forPolling; FOR info: REF ServerInfo _ serverList, info.next UNTIL info = NIL DO time: GMT = BasicTime.Now[]; ageOK: INT = BasicTime.Period[info.timeOK, time]; ageErr: INT = BasicTime.Period[info.timeErr, time]; { SELECT info.state FROM ok => IF ageOK > okTimeout THEN GO TO splice; noResponse => IF ageErr > noResponseTimeout THEN GO TO splice; noSuchPort => IF ageErr > noSuchPortTimeout THEN GO TO splice; ENDCASE => IF ageErr > errorTimeout THEN GO TO splice; last _ info; EXITS splice => IF last=NIL THEN serverList _ info.next ELSE last.next _ info.next; }; ENDLOOP; ENDLOOP; }; }. ¦FSFileLookupImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Schroeder, November 8, 1983 1:53 pm Levin, June 24, 1983 5:38 pm Russ Atkinson, March 18, 1985 10:41:54 pm PST Doug Wyatt (DKW), November 27, 1984 2:18:36 pm PST -- changed SetState Bob Hagmann April 30, 1985 1:05:25 pm PDT Exported to FSRemoteFile FileLookup protocol implementation keepingList => cache responses to try to reduce name lookup traffic and useless traffic when a server is obviously down Didn't find an entry, so make one DKW: formerly IF state = noSuchPort THEN info.state _ noSuchPort; seconds to wait before polling seconds to wait before having a cached OK server evaporate seconds to wait before having a noResponse evaporate seconds to wait before having a noSuchPort evaporate seconds to wait before having any other error evaporate Bob Hagmann April 29, 1985 10:25:49 am PDT changes to: DIRECTORY, FindServer Κλ– "Cedar" style˜šœ™Jšœ Οmœ7™BJ™#J™J™-J™FIcode™)—code1šΟk ˜ Lšœ žœžœ˜9Lšœ žœ ˜Lšœ žœ"˜4Lšœ žœ ˜Lšœžœ!˜.Lšœžœ½˜ΚLšœ žœ.˜˜ELšžœ ˜Lšœ˜L˜Lšžœžœžœžœ˜Lšžœžœ žœ˜Lšžœžœžœ˜—™code2šΟnœžœžœžœžœJžœ žœ˜ŽMšœžœ ˜Mšœ"˜"šžœ žœ˜Mšœ?˜?Mšœ˜Mšœ˜—Mšœ˜——™"Mšœ žœžœΟcœ˜;šœ žœžœ˜Mšœw™w—Mšœ žœ ˜6Mš œžœžœž œžœ žœ˜Gšœ žœžœ˜Mšœžœ˜ Mšœ˜Mšœ" '˜IMšœžœ ˜Mšœ žœ ˜"Mšœžœ ˜—šŸ œžœžœ žœžœ+žœžœ˜sMšžœžœžœ˜Mšœ ˜ šžœžœžœž˜4Mšžœžœžœžœ˜KMšžœ˜—M™!šœ˜Mšœ2˜2Mšœ˜šœT˜Tšœ˜šžœž˜Mšœ)˜)Mšžœ˜—Mšžœ˜ ——šžœžœ˜Mšœžœ˜šœžœ˜Mšœ(˜(Mšœžœ žœžœ˜8Mšœ žœ žœžœ˜9Mšœ˜—Mšžœžœžœžœ˜@Mšžœ žœ˜&Mšœ˜—Mšœ˜—Mšœ˜—šŸ œžœ"žœžœJžœ žœžœ˜§Mšœ#žœ˜2Mšœ(žœ˜7Mšœ(žœ˜7Mšœžœ˜Mšœžœ žœ(˜GMšœ˜Mšœžœ˜,Mšœ ˜%Mšœl˜lšžœ ž˜Mšœ2˜2Mšœ˜Mšœ?˜?šžœžœžœž˜*Mšœ$˜$Mšžœ˜—Mšœ.˜.Mšœ ˜ šœ˜Mšœ˜Mš žœžœžœžœ ˜(šžœ ž˜šœ˜Mšœžœžœžœžœž œžœžœžœ ˜jMšœ ˜ Mšœ˜šœ˜Mšœ#˜#Mšœžœ!žœ˜C—Mšœ,˜,Mšœ˜—Mšœ+˜+šœ žœ ž˜ Mšœ-˜-Mšœžœ˜!Mšžœ%žœ˜2—Mšžœ%žœ˜2—Mšœ˜Mšžœ˜Mšœ˜—Mšžœ˜—Mšœ˜Mšœ˜—š Ÿœžœžœžœž˜GMšžœžœ˜—š Ÿœžœžœžœž˜OMšžœžœ˜—šŸœžœžœžœ2˜QMšžœžœžœ˜Mšœžœ˜Mšžœ žœžœ˜?šžœž˜Mšœ-˜-Mšžœ˜—Mšœžœžœ™AMšœ˜M˜—šœžœ˜Mšœ™—šœ žœ˜Mšœ:™:—šœžœ˜Mšœ4™4—šœžœ˜Mšœ4™4—šœžœ˜Mšœ7™7—šŸœžœžœ˜Mšžœžœžœ˜šžœžœž˜Mšœžœžœ˜Mšœ ž œ-˜BMšžœ ˜š žœžœ$žœžœž˜DMšœžœ˜Mšœžœ'˜1Mšœžœ(˜3˜šžœ ž˜Mš œžœžœžœžœ˜-Mš œžœžœžœžœ˜>Mš œžœžœžœžœ˜>Mš žœžœžœžœžœ˜6—Mšœ ˜ šžœ ˜Mšžœžœžœžœ˜C—M˜—Mšžœ˜—Mšžœ˜—Mšœ˜——Lšœ˜K™K™™*Kšœ Οr™!—K™K™—…—κ!{