-- File: IFSFileImplA.mesa -- Last edited by: -- Levin - 13-Oct-81 9:09:48 DIRECTORY Heap USING [systemMDSZone, systemZone], IFSFile USING [Problem], IFSFilePrivate USING [ connectionTimeout, CopyString, fileLockTimeout, FinalizeFreeList, FSInstance, FSObject, InitializeFreeList], Leaf USING [ Answer, AnswerObject, LeafOp, leafSocket, paramsOp, ptLeaf, Request, RequestObject], PupDefs USING [ GetPupAddress, PupAddress, PupNameTrouble, PupPackageDestroy, PupPackageMake], Sequin USING [ Broken, Buffer, Create, Destroy, Get, GetEmptyBuffer, Handle, Put, ReleaseBuffer]; IFSFileImplA: MONITOR IMPORTS Heap, IFSFilePrivate, PupDefs, Sequin EXPORTS IFSFile, IFSFilePrivate = BEGIN OPEN IFSFilePrivate; -- Global Variables -- loginCount: CARDINAL; -- Miscellaneous -- someWordsForFilename: CARDINAL = 15; FilesInUse: ERROR = CODE; InsufficientLogouts: ERROR = CODE; PupBuffersTooSmall: ERROR = CODE; ServerNameMissing: ERROR = CODE; TooManyLogouts: ERROR = CODE; -- Procedures and Types Exported to IFSFile -- FSObject: PUBLIC TYPE = IFSFilePrivate.FSObject; Initialize: PUBLIC PROCEDURE = BEGIN zone ← Heap.systemZone; mdsZone ← Heap.systemMDSZone; loginCount ← 0; InitializeFreeList[]; END; Finalize: PUBLIC PROCEDURE = BEGIN IF loginCount ~= 0 THEN ERROR InsufficientLogouts; FinalizeFreeList[]; END; Login: PUBLIC PROCEDURE [ server, userName, password, secondaryName, secondaryPassword: LONG STRING ← NIL] RETURNS [fs: FSInstance] = BEGIN serverAddr: PupDefs.PupAddress ← [net: , host: , socket: Leaf.leafSocket]; sequin: Sequin.Handle; TryForConnection: PROCEDURE RETURNS [sequin: Sequin.Handle] = BEGIN LeafStringWords: PROCEDURE [s: LONG STRING] RETURNS [CARDINAL] = {RETURN[((IF s = NIL THEN 0 ELSE s.length)+1)/2+1]}; buffer: Sequin.Buffer ← Sequin.GetEmptyBuffer[]; adequate: CARDINAL = 2*(MAX[SIZE[Leaf.RequestObject], SIZE[Leaf.AnswerObject]] + 1 + LeafStringWords[userName] + LeafStringWords[password] + LeafStringWords[secondaryName] + LeafStringWords[secondaryPassword] + someWordsForFilename); problem: IFSFile.Problem; IF buffer.maxBytes < adequate THEN ERROR PupBuffersTooSmall; sequin ← Sequin.Create[dest: serverAddr, pupType: Leaf.ptLeaf]; LOOPHOLE[buffer.data, Leaf.Request]↑ ← [Leaf.paramsOp, params[packetDataBytes: buffer.maxBytes, fileLockTimeout: fileLockTimeout/5, connectionTimeout: connectionTimeout/5]]; buffer.nBytes ← Leaf.paramsOp.length; BEGIN ENABLE Sequin.Broken => {problem ← io; GO TO serverDead}; answerOp: Leaf.LeafOp; Sequin.Put[sequin, buffer]; buffer ← Sequin.Get[sequin]; answerOp ← LOOPHOLE[buffer.data, Leaf.Answer].op; Sequin.ReleaseBuffer[buffer]; IF answerOp.type ~= params OR answerOp.sense ~= reply THEN {problem ← other; GO TO serverDead}; EXITS serverDead => {Sequin.Destroy[sequin]; ERROR UnableToLogin[problem]}; END; END; GetPupAddress: PROCEDURE = BEGIN serverName: STRING ← mdsZone.NEW[StringBody[server.length]]; FOR i: CARDINAL IN [0..server.length) DO serverName[i] ← server[i]; ENDLOOP; serverName.length ← server.length; PupDefs.GetPupAddress[@serverAddr, serverName ! PupDefs.PupNameTrouble => BEGIN mdsZone.FREE[@serverName]; ERROR UnableToLogin[SELECT code FROM noRoute, noResponse => io, ENDCASE => other]; END]; mdsZone.FREE[@serverName]; END; NoteLogin: ENTRY PROCEDURE = INLINE {loginCount ← loginCount + 1}; IF server = NIL OR server.length = 0 THEN ERROR ServerNameMissing; PupDefs.PupPackageMake[]; GetPupAddress[]; sequin ← TryForConnection[]; fs ← zone.NEW[FSObject ← [ primaryName: CopyString[userName], primaryPassword: CopyString[password], secondaryName: CopyString[secondaryName], secondaryPassword: CopyString[secondaryPassword], serverAddr: serverAddr, cachedSequin: sequin, haveSequin: TRUE]]; NoteLogin[]; END; UnableToLogin: PUBLIC ERROR [reason: IFSFile.Problem] = CODE; Logout: PUBLIC PROCEDURE [fs: FSInstance] = BEGIN NoteLogout: ENTRY PROCEDURE = INLINE {loginCount ← loginCount - 1}; IF loginCount = 0 THEN ERROR TooManyLogouts; IF fs.fileList ~= NIL THEN ERROR FilesInUse; IF fs.primaryName ~= NIL THEN zone.FREE[@fs.primaryName]; IF fs.primaryPassword ~= NIL THEN zone.FREE[@fs.primaryPassword]; IF fs.secondaryName ~= NIL THEN zone.FREE[@fs.secondaryName]; IF fs.secondaryPassword ~= NIL THEN zone.FREE[@fs.secondaryPassword]; IF fs.haveSequin THEN Sequin.Destroy[fs.cachedSequin]; zone.FREE[@fs]; PupDefs.PupPackageDestroy[]; NoteLogout[]; END; -- Procedures and Variables Exported to IFSFilePrivate -- zone: PUBLIC UNCOUNTED ZONE; mdsZone: PUBLIC MDSZone; GetSequinForFS: PUBLIC ENTRY PROCEDURE [fs: FSInstance] RETURNS [sequin: Sequin.Handle, fromCache: BOOLEAN] = BEGIN IF (fromCache ← fs.haveSequin) THEN {fs.haveSequin ← FALSE; sequin ← fs.cachedSequin} ELSE sequin ← Sequin.Create[dest: fs.serverAddr, pupType: Leaf.ptLeaf]; END; FreeSequinForFS: PUBLIC ENTRY PROCEDURE [ fs: FSInstance, sequin: Sequin.Handle, toCache: BOOLEAN ← TRUE] = BEGIN -- we cache the newest one to minimize the chance of subsequent timeout IF ~toCache THEN {Sequin.Destroy[sequin]; RETURN}; IF fs.haveSequin THEN Sequin.Destroy[fs.cachedSequin]; fs.cachedSequin ← sequin; fs.haveSequin ← TRUE; END; END.