AlpInstanceImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by
Kolling on October 18, 1983 3:51 pm
MBrown on February 2, 1984 10:55:52 am PST
Hauser, March 15, 1985 1:57:19 pm PST
Bob Hagmann June 3, 1985 12:53:06 pm PDT
Carl Hauser, March 27, 1987 1:34:31 pm PST
DIRECTORY
AlpineEmergency,
AlpineEnvironment
USING[Conversation, FileStore, LockFailure, NeededAccess, OperationFailure, Principal,
UnknownType],
AlpineFile
USING[AccessFailed, LockFailed, OperationFailed, PossiblyDamaged, StaticallyInvalid, Unknown],
AlpineFileRpcControl
USING[ImportNewInterface],
AlpineImportLocal
USING[ImportIfLocal],
AlpineOwnerRpcControl
USING[ImportNewInterface],
AlpineTransactionRpcControl
USING[ImportNewInterface],
AlpineVolumeRpcControl
USING[ImportNewInterface],
AlpInstance
USING[Failure, Handle, Object],
AlpPrivate
USING[InterfaceCreatorProc],
Booting
USING[RegisterProcs, RollbackProc],
ClientMap
USING[GetName, Register],
GVNames
USING[AuthenticateKey],
Rope
USING[Cat, Equal, ROPE],
RPC
USING[AuthenticateFailed, EncryptionKey, GenerateConversation,
GetCaller, ImportFailed, MakeKey, StartConversation, VersionRange],
RuntimeError
USING[UNCAUGHT],
UserCredentials
USING[Get];
AlpInstanceImpl: CEDAR MONITOR
IMPORTS AlpineEmergency, AF: AlpineFile, AlpineFileRpcControl, AlpineImportLocal,
AlpineOwnerRpcControl, AlpineTransactionRpcControl, AlpineVolumeRpcControl, Booting, ClientMap, GVNames, Rope,
RPC, RuntimeError, UserCredentials
EXPORTS AlpInstance, AlpPrivate
SHARES AlpineFileRpcControl, AlpineOwnerRpcControl, AlpineTransactionRpcControl,
AlpineVolumeRpcControl =
BEGIN OPEN AE: AlpineEnvironment, AlpI: AlpInstance, RuntimeError;
cacheRec: TYPE = RECORD [
object: AlpI.Handle ← NIL,
local: BOOLFALSE
];
objectCache: LIST OF cacheRec ← NIL;
localFileStore: AE.FileStore ← "Local.alpine";
LocalAuthenticateFailed: ERROR = CODE;
FindObjectInCache: INTERNAL PROCEDURE[fileStore: AE.FileStore, caller: AE.Principal, key:
RPC.EncryptionKey] RETURNS[handle: AlpI.Handle ← NIL] =
BEGIN
conversation: AE.Conversation ← NIL;
local: BOOLFALSE;
FOR list: LIST OF cacheRec ← objectCache, list.rest UNTIL list = NIL DO
IF Rope.Equal[list.first.object.fileStore, fileStore, FALSE]
THEN BEGIN
TRUSTED BEGIN
IF list.first.local THEN {
local ← TRUE;
IF (Rope.Equal[ClientMap.GetName[list.first.object.conversation], caller, FALSE]) AND (key = list.first.object.key)
THEN conversation ← list.first.object.conversation
}
ELSE
IF Rope.Equal[RPC.GetCaller[list.first.object.conversation], caller, FALSE] AND (key = list.first.object.key)
THEN conversation ← list.first.object.conversation
END;
IF handle = NIL THEN handle ← NEW[AlpI.Object ← [
trans: list.first.object.trans,
file: list.first.object.file,
owner: list.first.object.owner,
volume: list.first.object.volume,
otherInterfaces: list.first.object.otherInterfaces,
conversation: conversation,
key: key,
fileStore: fileStore]];
IF conversation # NIL THEN {
handle.conversation ← conversation;
RETURN;
};
END;
ENDLOOP;
IF handle # NIL THEN {
fileStore found in cache but no match on caller and key
IF local THEN {
IF GVNames.AuthenticateKey[caller, key] # individual THEN ERROR LocalAuthenticateFailed;
handle.conversation ← RPC.GenerateConversation[];
TRUSTED { ClientMap.Register[handle.conversation, caller] };
}
ELSE handle.conversation ← RPC.StartConversation[caller, key, fileStore, authOnly];
}
ELSE {
Nothing found in cache. Check to see if server enabled locally and is the one we want.
handle ← NEW[AlpI.Object ← [
trans: NIL,
file: NIL,
owner: NIL,
volume: NIL,
otherInterfaces: NIL,
conversation: NIL,
key: key,
fileStore: fileStore]];
IF AlpineImportLocal.ImportIfLocal[handle, fileStore] THEN TRUSTED {
IF GVNames.AuthenticateKey[caller, key] # individual THEN ERROR LocalAuthenticateFailed;
handle.conversation ← RPC.GenerateConversation[];
ClientMap.Register[handle.conversation, caller];
local ← TRUE;
}
ELSE {
suffix: Rope.ROPE ← "alpine";
tryAgain: BOOLFALSE;
TRUSTED BEGIN handle.conversation ← RPC.StartConversation[caller, key, fileStore, authOnly]; END;
handle.trans ← AlpineTransactionRpcControl.ImportNewInterface[
[type: Rope.Cat["AlpineTransaction.", suffix], instance: fileStore, version: version],
[NIL, NIL, NIL] !
RPC.ImportFailed =>
IF why=wrongVersion THEN {tryAgain ← TRUE; CONTINUE} ELSE REJECT
];
IF tryAgain THEN {
suffix ← "newAlpine";
handle.trans ← AlpineTransactionRpcControl.ImportNewInterface[
[type: Rope.Cat["AlpineTransaction.", suffix], instance: fileStore, version: version],
[NIL, NIL, NIL]
];
};
handle.file ← AlpineFileRpcControl.ImportNewInterface[
[type: Rope.Cat["AlpineFile.", suffix], instance: fileStore, version: version],
[NIL, NIL, NIL]
];
handle.owner ← AlpineOwnerRpcControl.ImportNewInterface[
[type: Rope.Cat["AlpineOwner.", suffix], instance: fileStore, version: version],
[NIL, NIL, NIL]
];
handle.volume ← AlpineVolumeRpcControl.ImportNewInterface[[type:
Rope.Cat["AlpineVolume.", suffix], instance: fileStore, version: version],
[NIL, NIL, NIL]
];
};
FOR list: LIST OF AlpPrivate.InterfaceCreatorProc ← interfaceCreators, list.rest
UNTIL list = NIL
DO
handle.otherInterfaces ← CONS[list.first[fileStore, version], handle.otherInterfaces];
ENDLOOP;
};
objectCache ← CONS[ [handle, local], objectCache];
END;
Create: PUBLIC ENTRY PROCEDURE[fileStore: AE.FileStore, caller: AE.Principal, key:
RPC.EncryptionKey] RETURNS [handle: AlpI.Handle] =
non system-fatal errors:
Failed[alpineDownOrCommunications, alpineDown, authenticateFailed, badCallee, grapevineDownOrCommunications, mismatch].
caller = NIL means the logged-in user.
BEGIN
ENABLE UNWIND => NULL;
BEGIN
ENABLE BEGIN
RPC.AuthenticateFailed => SELECT why FROM
badCaller, badKey => GOTO authenticateFailed;
badCallee => GOTO badCallee;
communications => GOTO grapevineDownOrCommunications;
ENDCASE => NULL;
LocalAuthenticateFailed => GOTO authenticateFailed;
RPC.ImportFailed => SELECT why FROM
communications => GOTO alpineDownOrCommunications; -- almost certainly alpine and not grapevine, since authenticate got through.
wrongVersion, stubProtocol => GOTO mismatch;
unbound => GOTO alpineDown;
ENDCASE => NULL;
END;
startedAlready ← TRUE;
IF caller = NIL
THEN BEGIN psw: Rope.ROPE;
[caller, psw] ← UserCredentials.Get[];
TRUSTED BEGIN key ← RPC.MakeKey[psw]; END;
END;
handle ← FindObjectInCache[fileStore, caller, key];
IF Rope.Equal[fileStore, localFileStore, FALSE]
THEN BEGIN
-- The following requires attention to get local.alpine working. Specifically, the interface records require procedures having an additional first parameter which is not in e.g. AT.Create.
GOTO badCallee;
conversation: AE.Conversation;
IF NOT PrincOpsUtils.IsBound[LOOPHOLE[AT.Create]] THEN GOTO alpineDownOrCommunications;
TRUSTED BEGIN
conversation ← RPC.GenerateConversation[];
ClientMap.Register[conversation, caller];
END;
handle ← NEW[AlpI.Object ← [
trans: AlpineTransactionRpcControl.NewInterfaceRecord[],
file: AlpineFileRpcControl.NewInterfaceRecord[],
owner: AlpineOwnerRpcControl.NewInterfaceRecord[],
volume: AlpineVolumeRpcControl.NewInterfaceRecord[],
otherInterfaces: NIL,
conversation: conversation,
key: key,
fileStore: fileStore]];
handle.trans^ ← [clientStubCreate: AT.Create, clientStubCreateWorker: AT.CreateWorker, clientStubAssertAlpineWheel: AT.AssertAlpineWheel, clientStubFinish: AT.Finish, Unknown: AT.Unknown, OperationFailed: AT.OperationFailed];
handle.file^ ← [clientStubOpen: AF.Open, clientStubCreate: AF.Create, clientStubClose: AF.Close, clientStubDelete: AF.Delete, clientStubGetUniversalFile: AF.GetUniversalFile, clientStubGetTransID: AF.GetTransID, clientStubGetAccessRights: AF.GetAccessRights, clientStubGetLockOption: AF.GetLockOption, clientStubSetLockOption: AF.SetLockOption, clientStubGetRecoveryOption: AF.GetRecoveryOption, clientStubGetReferencePattern: AF.GetReferencePattern, clientStubSetReferencePattern: AF.SetReferencePattern, clientStubReadPages: AF.ReadPages, clientStubWritePages: AF.WritePages, clientStubLockPages: AF.LockPages, clientStubUnlockPages: AF.UnlockPages, clientStubReadProperties: AF.ReadProperties, clientStubWriteProperties: AF.WriteProperties, clientStubUnlockVersion: AF.UnlockVersion, clientStubIncrementVersion: AF.IncrementVersion, clientStubGetSize: AF.GetSize, clientStubSetSize: AF.SetSize, AccessFailed: AF.AccessFailed, LockFailed: AF.LockFailed, OperationFailed: AF.OperationFailed, StaticallyInvalid: AF.StaticallyInvalid, Unknown: AF.Unknown, PossiblyDamaged: AF.PossiblyDamaged];
handle.owner^ ← [clientStubReadProperties: AO.ReadProperties, clientStubWriteProperties: AO.WriteProperties, clientStubCreate: AO.Create, clientStubDestroy: AO.Destroy, clientStubReadNext: AO.ReadNext, clientStubReadDBProperties: AO.ReadDBProperties, clientStubReorganizeDB: AO.ReorganizeDB, AccessFailed: AO.AccessFailed, LockFailed: AO.LockFailed, OperationFailed: AO.OperationFailed, StaticallyInvalid: AO.StaticallyInvalid, Unknown: AO.Unknown];
handle.volume^ ← [clientStubGetNextGroup: AV.GetNextGroup, clientStubGetGroup: AV.GetGroup, clientStubGetEnclosingGroup: AV.GetEnclosingGroup, AccessFailed: AV.AccessFailed, Unknown: AV.Unknown, StaticallyInvalid: AV.StaticallyInvalid];
FOR list: LIST OF AlpPrivate.InterfaceCreatorProc ← interfaceCreators, list.rest UNTIL list = NIL DO
handle.otherInterfaces ← CONS[list.first[fileStore, version], handle.otherInterfaces];
ENDLOOP;
END
ELSE handle ← FindObjectInCache[fileStore, caller, key];
EXITS
alpineDownOrCommunications => RETURN WITH ERROR Failed[alpineDownOrCommunications];
alpineDown => RETURN WITH ERROR Failed[alpineDown];
authenticateFailed => RETURN WITH ERROR Failed[authenticateFailed];
badCallee => RETURN WITH ERROR Failed[badCallee];
grapevineDownOrCommunications => RETURN WITH ERROR Failed[grapevineDownOrCommunications];
mismatch => RETURN WITH ERROR Failed[mismatch];
END;
END;
If a object in our cache has an InterfaceRecord matching an InterfaceRecord in this handle, throw out the object. I think one interface matching means all match.....
NoticeUnboundInstance: PUBLIC ENTRY PROCEDURE[handle: AlpI.Handle] =
non system-fatal errors:
none.
BEGIN
ENABLE {
UNWIND => AlpineEmergency.UnwindingMonitor[];
UNCAUGHT => {AlpineEmergency.UncaughtThruMonitor[]; REJECT};
};
prevEntry: LIST OF cacheRec ← NIL;
list: LIST OF cacheRec ← objectCache;
DO
IF list = NIL THEN EXIT;
IF list.first.object.trans = handle.trans
THEN BEGIN
IF prevEntry = NIL
THEN objectCache ← list.rest
ELSE prevEntry.rest ← list.rest;
END
ELSE prevEntry ← list;
list ← list.rest;
ENDLOOP;
END;
RegisterInterfaceCreator: PUBLIC ENTRY PROCEDURE[proc: AlpPrivate.InterfaceCreatorProc] =
non system-fatal errors:
none.
BEGIN
ENABLE {
UNWIND => AlpineEmergency.UnwindingMonitor[];
UNCAUGHT => {AlpineEmergency.UncaughtThruMonitor[]; REJECT};
};
IF startedAlready THEN ERROR;
interfaceCreators ← CONS[proc, interfaceCreators];
END;
interfaceCreators: LIST OF AlpPrivate.InterfaceCreatorProc ← NIL;
startedAlready: BOOLEANFALSE;
AlpRollbackProcedure: ENTRY Booting.RollbackProc = -- TYPE = PROC[clientData: REF ANY];
non system-fatal errors:
none.
BEGIN
ENABLE {
UNWIND => AlpineEmergency.UnwindingMonitor[];
UNCAUGHT => {AlpineEmergency.UncaughtThruMonitor[]; REJECT};
};
objectCache ← NIL;
END;
Failed: PUBLIC ERROR [why: AlpInstance.Failure] = CODE;
AccessFailed: PUBLIC ERROR [missingAccess: AE.NeededAccess] ← AF.AccessFailed;
LockFailed: PUBLIC ERROR [why: AE.LockFailure] ← AF.LockFailed;
OperationFailed: PUBLIC ERROR [why: AE.OperationFailure] ← AF.OperationFailed;
StaticallyInvalid: PUBLIC ERRORAF.StaticallyInvalid;
Unknown: PUBLIC ERROR [what: AE.UnknownType] ← AF.Unknown;
PossiblyDamaged: PUBLIC SIGNALLOOPHOLE[AF.PossiblyDamaged];
version: RPC.VersionRange = [6, 6];
start up code.
TRUSTED { Booting.RegisterProcs[c: , r: AlpRollbackProcedure]; };
END.
Edit Log
Initial: Kolling: February 15, 1983 2:58 pm.
Changed: MBrown: February 1, 1984 8:27:49 pm PST. Rolled version stamp.
Hauser, March 15, 1985 11:58:11 am PST
Added copyright; changes for Cedar6.0 Lupine. Create for local.alpine requires further attention before it can work.
changes to: FindObjectInCache, Create
Bob Hagmann June 3, 1985 12:53:20 pm PDT
added code to handle local imports
Carl Hauser, August 11, 1985 1:00:42 pm PDT
changes to: FindObjectInCache: changed so that for any [fileStore, caller, key] triple there is at most one conversation.