-- FileLookupImpl.mesa -- M. D. Schroeder, September 7, 1982 11:50 am DIRECTORY ConvertUnsafe: TYPE USING [AppendRope], FileLookup: TYPE, Mopcodes: TYPE USING [zEXCH], Process: TYPE USING [Detach, SecondsToTicks], PupDefs: TYPE USING [GetFreePupBuffer, GetHopsToNetwork, GetPupAddress, MsToTocks, PupAddress, PupNameTrouble, PupBuffer, PupSocket, PupSocketDestroy, PupSocketMake, ReturnFreePupBuffer, SetPupContentsBytes], PupTypes: TYPE USING [fillInSocketID, Pair, PupSocketID, PupType], Rope: TYPE USING [ Cat, Compare, Fetch, Index, Length, ROPE, Substr ], Runtime: TYPE USING [BoundsFault], System: TYPE USING [GetGreenwichMeanTime, GreenwichMeanTime]; FileLookupImpl: MONITOR IMPORTS ConvertUnsafe, Process, PupDefs, Rope, Runtime, System EXPORTS FileLookup = BEGIN OPEN FileLookup; ROPE: TYPE = Rope.ROPE; ReverseCardinal: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL]; ServerInfo: TYPE = RECORD [ name: ROPE, addr: PupDefs.PupAddress, state: Result, -- can be noResponse, noSuchPort, or ok -- time: System.GreenwichMeanTime, -- GMT of last ok or first not ok -- next: REF ServerInfo]; serverList: REF ServerInfo _ NIL; -- list of known servers -- packetCount: LONG CARDINAL _ 0; -- outgoing; also used as pupID -- LookupFile: PUBLIC SAFE PROC [server, file: ROPE ] RETURNS [result: Result, version: CARDINAL, create: System.GreenwichMeanTime, count: LONG CARDINAL] = TRUSTED BEGIN sI: REF ServerInfo; [result, sI] _ FindServer[server]; IF result = ok THEN BEGIN [result, version, create, count] _ DoFileLookup[sI.addr, IFSSyntax[file]]; SetState[sI, result]; END; END; --RemoteFileLookup-- FindServer: ENTRY PROC [server: ROPE] RETURNS [result: Result, info: REF ServerInfo] = -- noResponse => NLS didn't respond, no route to server, -- -- or server didn't respond last time -- -- noSuchPort => server responded with noSuchPort last time; -- -- noSuchName => server not in NLS data base; info may be NIL -- -- ok => info.addr is valid and server may be up; try a DoFileLookup -- BEGIN addr: PupDefs.PupAddress; serverStr: STRING _ [32]; result _ ok; FOR info _ serverList, info.next UNTIL info = NIL DO IF Rope.Compare[server, info.name, FALSE] = equal THEN {result _ info.state; RETURN}; ENDLOOP; -- didn't find the entry, so make one -- ConvertUnsafe.AppendRope[from: server, to: serverStr ! Runtime.BoundsFault => CONTINUE]; PupDefs.GetPupAddress[@addr, serverStr ! PupDefs.PupNameTrouble => {SELECT code FROM noRoute, noResponse => result _ noResponse; errorFromServer => result _ noSuchName; ENDCASE => ERROR; CONTINUE} ]; IF result = noSuchName THEN RETURN; info _ NEW [ServerInfo _ [name: server, addr: addr, state: result, time: System.GetGreenwichMeanTime[], next: serverList]]; IF serverList = NIL THEN Process.Detach[FORK ServerCollector[]]; serverList _ info; END; --FindServer-- DoFileLookup: PROC [addr: PupDefs.PupAddress, file: ROPE ] RETURNS [result: Result, version: CARDINAL, create: System.GreenwichMeanTime, count: LONG CARDINAL] = BEGIN LookupFileType: PupTypes.PupType = LOOPHOLE[200B]; LookupFileReplyType: PupTypes.PupType = LOOPHOLE[201B]; LookupFileErrorType: PupTypes.PupType = LOOPHOLE[202B]; LookupFileSocket: PupTypes.PupSocketID = [0, 61B]; 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 -- addr.socket _ LookupFileSocket; 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]; BEGIN r: PupDefs.PupBuffer = s.get[]; IF r = NIL THEN LOOP; -- no response yet SELECT r.pupType FROM LookupFileReplyType => BEGIN rPtr: LONG POINTER TO MACHINE DEPENDENT RECORD [v: CARDINAL, c, l: ReverseCardinal] = LOOPHOLE[@r.pupBody]; result _ ok; version _ rPtr.v; create _ GMTFromReverseCardinal[rPtr.c]; count _ LongCardFromReverseCardinal[rPtr.l]; END; LookupFileErrorType => result _ noSuchName; error => SELECT r.errorCode FROM noProcessPupErrorCode => result _ noSuchPort; cantGetTherePupErrorCode => NULL; ENDCASE => {PupDefs.ReturnFreePupBuffer[r]; LOOP}; ENDCASE => {PupDefs.ReturnFreePupBuffer[r]; LOOP}; PupDefs.ReturnFreePupBuffer[r]; EXIT; END; ENDLOOP; PupDefs.PupSocketDestroy[s]; END; --DoFileLookup-- IFSSyntax: PROC [name: ROPE] RETURNS [iName: ROPE] = BEGIN start, end: INT; length: INT = Rope.Length[name]; start _ 0; IF (end _ Rope.Index[name, start, "/"]) = length THEN RETURN [name]; iName _ "<"; DO iName _ Rope.Cat[iName, Rope.Substr[name, start, end-start]]; IF end = length THEN EXIT; iName _ Rope.Cat[iName, ">"]; start _ end + 1; end _ Rope.Index[name, start, "/"]; ENDLOOP; END; --IFSSyntax-- PupIDFromLongCardinal: PROC [s: LONG CARDINAL] RETURNS [PupTypes.Pair] = MACHINE CODE {Mopcodes.zEXCH}; GMTFromReverseCardinal: PROC [r: ReverseCardinal] RETURNS [System.GreenwichMeanTime] = MACHINE CODE {Mopcodes.zEXCH}; LongCardFromReverseCardinal: PROC [r: ReverseCardinal] RETURNS [LONG CARDINAL] = MACHINE CODE {Mopcodes.zEXCH}; SetState: ENTRY PROC [info: REF ServerInfo, state: Result] = BEGIN info.time _ System.GetGreenwichMeanTime[]; SELECT state FROM noResponse, noSuchPort => info.state _ state; ENDCASE; -- info.state will be ok already -- END; --SetState-- ServerCollector: ENTRY PROC = BEGIN forOneMinute: CONDITION _ [Process.SecondsToTicks[60]]; UNTIL serverList = NIL DO last: REF ServerInfo _ NIL; info: REF ServerInfo; WAIT forOneMinute; FOR info _ serverList, info.next UNTIL info = NIL DO age: LONG CARDINAL = System.GetGreenwichMeanTime[] - info.time; IF (info.state # ok AND age > 300) OR (age > 1800) THEN -- remove this entry from the list -- IF last=NIL THEN serverList _ info.next ELSE last.next _ info.next ELSE -- entry hasn't aged enough -- last _ info; ENDLOOP; ENDLOOP; END; --ServerCollector-- END...