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