DIRECTORY BasicTime USING [FromPupTime, GMT, Now, nullGMT, Period], Endian USING [FWORD, CardFromF], FSBackdoor USING [Version], FSRemoteFile USING [GetServerPupName, LookupResult], Process USING [Detach, Ticks, SecondsToTicks], Pup USING [Address], PupBuffer USING [Buffer], PupHop USING [InitialTimeout], PupName USING [NameLookup, Error], PupSocket USING [AllocBuffer, CopyRope, CreateEphemeral, Destroy, FreeBuffer, Get, GetUniqueID, Send, SetNoErrors, Socket], PupType USING [fileLookup, fileLookupError, fileLookupReply], PupWKS USING [fileLookup], Rope USING [Equal, ROPE], RuntimeError USING [UNCAUGHT]; FSFileLookupImpl: CEDAR MONITOR IMPORTS BasicTime, Endian, FSRemoteFile, Process, PupHop, PupName, PupSocket, 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 pup id ServerInfo: TYPE = RECORD [ name: ROPE, addr: Pup.Address, 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; { name: ROPE _ FSRemoteFile.GetServerPupName[server]; addr: Pup.Address; addr _ PupName.NameLookup[name, PupWKS.fileLookup ! PupName.Error => { 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: Pup.Address, file: ROPE] RETURNS [result: FSRemoteFile.LookupResult, version: FSBackdoor.Version, create: GMT, count: INT] = TRUSTED { tries: CARDINAL = 4; msWait: CARDINAL _ PupHop.InitialTimeout[addr.net, 2000]; id: Endian.FWORD _ PupSocket.GetUniqueID[]; socket: PupSocket.Socket; result _ noResponse; -- assume result IF msWait = 0 THEN RETURN; socket _ PupSocket.CreateEphemeral[remote: addr, getTimeout: msWait]; PupSocket.SetNoErrors[socket]; FOR i: NAT IN [0..tries) DO b: PupBuffer.Buffer _ PupSocket.AllocBuffer[socket]; b.type _ PupType.fileLookup; b.id _ id; PupSocket.CopyRope[b, file]; PupSocket.Send[socket, b, addr]; b _ PupSocket.Get[socket]; IF b = NIL THEN LOOP; -- no response yet IF b.id # id THEN { PupSocket.FreeBuffer[b]; LOOP; }; SELECT b.type FROM PupType.fileLookupReply => { result _ ok; version _ [b.fileLookupReply.version]; create _ BasicTime.FromPupTime[Endian.CardFromF[b.fileLookupReply.createTime] ! RuntimeError.UNCAUGHT => {create _ BasicTime.nullGMT; CONTINUE}]; count _ Endian.CardFromF[b.fileLookupReply.length]; }; PupType.fileLookupError => result _ noSuchFile; error => SELECT b.error.code FROM noSocket => result _ noSuchPort; cantGetThere => NULL; ENDCASE => { PupSocket.FreeBuffer[b]; LOOP; }; ENDCASE => { PupSocket.FreeBuffer[b]; LOOP; }; PupSocket.FreeBuffer[b]; EXIT; ENDLOOP; PupSocket.Destroy[socket]; }; 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 Hal Murray, June 3, 1986 4:33:20 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 Κf– "Cedar" style˜šœ™Jšœ Οmœ7™BJ™#J™J™-J™FIcode™)K™'—code1šΟk ˜ Lšœ žœžœ˜9Lšœžœžœ ˜ Lšœ žœ ˜Lšœ žœ"˜4Lšœžœ!˜.Lšœžœ ˜Lšœ žœ ˜Lšœžœ˜Lšœžœ˜"Lšœ žœl˜{Lšœžœ0˜=Lšœžœ˜Lšœžœ žœ˜Lšœ žœžœ˜—šœžœž˜LšžœY˜`Lšžœ ˜Lšœ˜L˜Lšžœžœžœžœ˜Lšžœžœ žœ˜Lšžœžœžœ˜—™code2šΟnœžœžœžœžœJžœ žœ˜ŽMšœžœ ˜Mšœ"˜"šžœ žœ˜Mšœ?˜?Mšœ˜Mšœ˜—Mšœ˜——™"Mšœ žœžœΟcœ˜;šœ žœžœ˜Mšœw™w—Mšœ žœ  ˜7šœ žœžœ˜Mšœžœ˜ Mšœ˜Mšœ" '˜IMšœžœ ˜Mšœ žœ ˜"Mšœžœ ˜—šŸ œžœžœ žœžœ+žœžœ˜sMšžœžœžœ˜Mšœ ˜ šžœžœžœž˜4Mšžœžœžœžœ˜KMšžœ˜—M™!šœ˜Mšœ3˜3Mšœ˜šœ1˜1šœ˜šžœž˜Mšœ)˜)Mšžœ˜—Mšžœ˜ ——šžœžœ˜Mšœžœ˜šœžœ˜Mšœ(˜(Mšœžœ žœžœ˜8Mšœ žœ žœžœ˜9Mšœ˜—Mšžœžœžœžœ˜@Mšžœ žœ˜&Mšœ˜—Mšœ˜—Mšœ˜—šŸ œžœžœžœJžœ žœžœ˜ Mšœžœ˜Mšœžœ)˜9Mšœ žœ˜+Mšœ˜Mšœ ˜%Mšžœ žœžœ˜MšœE˜EKšœ˜šžœžœžœ ž˜Mšœ4˜4Mšœ˜Mšœ ˜ Mšœ˜Mšœ ˜ Mšœ˜Mš žœžœžœžœ ˜(Mšžœ žœžœ˜5šžœž˜šœ˜Mšœ ˜ Mšœ&˜&šœM˜MMšœžœ!žœ˜C—Mšœ6˜6—Mšœ/˜/šœ žœž˜!Mšœ ˜ Mšœžœ˜Mšžœžœ˜.—Mšžœžœ˜.—Mšœ˜Mšžœ˜Mšžœ˜—Mšœ˜Mšœ˜—šŸœžœžœžœ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šœžœ(˜3Mšœ˜šžœ ž˜Mš œžœžœžœžœ˜-Mš œžœžœžœžœ˜>Mš œžœžœžœžœ˜>Mš žœžœžœžœžœ˜6—Mšœ ˜ šžœ ˜Mšžœžœžœžœ˜F—Mšžœ˜—Mšžœ˜—Mšœ˜——Lšœ˜K™K™™*Kšœ Οr™!—K™K™—…—†Ί