IFSFileImplA.mesa
Levin - 13-Oct-81 9:09:48
Russ Atkinson, November 9, 1983 9:00 pm
DIRECTORY
IFSFile USING [Problem],
IFSFilePrivate USING [
connectionTimeout, fileLockTimeout, FinalizeFreeList, FSInstance, FSObject, InitializeFreeList],
Leaf USING [
Answer, AnswerObject, LeafOp, leafSocket, paramsOp, ptLeaf, Request, RequestObject],
PupDefs USING [
GetPupAddress, PupAddress, PupNameTrouble, PupPackageDestroy, PupPackageMake],
Rope,
Sequin USING [
Broken, Buffer, Create, Destroy, Get, GetEmptyBuffer, Handle, Put, ReleaseBuffer];
IFSFileImplA: MONITOR
IMPORTS IFSFilePrivate, PupDefs, Rope, Sequin
EXPORTS IFSFile, IFSFilePrivate = {
OPEN IFSFilePrivate;
ROPE: TYPE = Rope.ROPE;
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 PROC = {
loginCount ← 0;
InitializeFreeList[];
};
Finalize: PUBLIC PROC = {
IF loginCount ~= 0 THEN ERROR InsufficientLogouts;
FinalizeFreeList[];
};
LeafStringWords: PROC [r: ROPE] RETURNS [CARDINAL] = {
RETURN[((Rope.Length[r])+1)/2+1];
};
Login: PUBLIC PROC
[server, userName, password, secondaryName, secondaryPassword: ROPENIL]
RETURNS [fs: FSInstance] = {
serverAddr: PupDefs.PupAddress ← [net: [0], host: [0], socket: Leaf.leafSocket];
sequin: Sequin.Handle;
TryForConnection: PROC RETURNS [sequin: Sequin.Handle] = {
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;
{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]};
};
};
GetPupAddress: PROC = {
serverAddr ← PupDefs.GetPupAddress[Leaf.leafSocket, server
! PupDefs.PupNameTrouble => {
ERROR UnableToLogin[SELECT code FROM noRoute, noResponse => io, ENDCASE => other];
}];
};
NoteLogin: ENTRY PROC = INLINE {loginCount ← loginCount + 1};
IF Rope.Length[server] = 0 THEN ERROR ServerNameMissing;
PupDefs.PupPackageMake[];
GetPupAddress[];
sequin ← TryForConnection[];
fs ← NEW[FSObject ← [
primaryName: userName, primaryPassword: password,
secondaryName: secondaryName,
secondaryPassword: secondaryPassword,
serverAddr: serverAddr,
cachedSequin: sequin, haveSequin: TRUE]];
NoteLogin[];
};
UnableToLogin: PUBLIC ERROR [reason: IFSFile.Problem] = CODE;
Logout: PUBLIC PROC [fs: FSInstance] = {
NoteLogout: ENTRY PROC = INLINE {loginCount ← loginCount - 1};
IF loginCount = 0 THEN ERROR TooManyLogouts;
IF fs.fileList ~= NIL THEN ERROR FilesInUse;
IF fs.primaryName ~= NIL THEN fs.primaryName ← NIL;
IF fs.primaryPassword ~= NIL THEN fs.primaryPassword ← NIL;
IF fs.secondaryName ~= NIL THEN fs.secondaryName ← NIL;
IF fs.secondaryPassword ~= NIL THEN fs.secondaryPassword ← NIL;
IF fs.haveSequin THEN {Sequin.Destroy[fs.cachedSequin]; fs.cachedSequin ← NIL};
PupDefs.PupPackageDestroy[];
NoteLogout[];
};
Procedures and Variables Exported to IFSFilePrivate --
GetSequinForFS: PUBLIC ENTRY PROC [fs: FSInstance]
RETURNS [sequin: Sequin.Handle, fromCache: BOOL] = {
IF (fromCache ← fs.haveSequin) THEN
{fs.haveSequin ← FALSE; sequin ← fs.cachedSequin}
ELSE sequin ← Sequin.Create[dest: fs.serverAddr, pupType: Leaf.ptLeaf];
};
FreeSequinForFS: PUBLIC ENTRY PROC [
fs: FSInstance, sequin: Sequin.Handle, toCache: BOOLTRUE] = {
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;
};
}.