LarkSmartsInitImpl.mesa
Last modified by D. Swinehart, March 6, 1985 3:45:05 pm PST
Last Edited by: Pier, May 3, 1984 2:52:59 pm PDT
DIRECTORY
Commander USING [ CommandProc, Register ],
IO,
Lark -- USING [
-- CommandEvents, ConnectionSpec, Event, LarkModel, Passel, SHHH, StatusEvent, StatusEvents ]--,
LarkRpcControl USING [ ImportNewInterface, InterfaceRecord ],
LarkSmarts,
LarkSmartsMonitorImpl,
LarkSmartsRpcControl USING [ExportInterface, InterfaceName, UnexportInterface],
Log USING [ DNFProc, RegisterWhereToReport, ReportFR, Problem, ProblemFR, WhereProc ],
LupineRuntime,
Names USING [CmdOrToken, CurrentPasskey, RnameToRspec, Rspec ],
NamesRPC USING [ StartConversation ],
Nice USING [ LarkConLogStream ],
RPC USING [ AuthenticateFailed, EncryptionKey, ExportFailed, GetCaller, ImportFailed ],
SafeStorage USING [ GetCanonicalType, Type ],
ThNet USING [ pd ],
ThPartyPrivate USING [ DehandleSmarts, LocalSmartsInterface, RegisterLocal, SmartsBody, SmartsData, GetPartySmarts ],
ThParty USING [ CreateParty, Deregister, Enable ],
Thrush USING [
CallUrgency, ConversationHandle, Disposition, epoch, Epoch, H, NetAddress, none, nullHandle, PartyHandle, ROPE, SmartsHandle, ThHandle, unencrypted ],
ThSmartsPrivate USING [
CheckHookState, EnterLarkState, GetSmartsInfo, LarkFailed, LarkInfo, LarkInfoBody, LarkParseEvent, LarkProgress, LarkSupervise, RegisterTrunk, SmartsInfo, SmartsInfoBody ],
ThSmartsRpcControl,
ThVersions,
Triples USING [ Erase, Make ],
TU
;
LarkSmartsInitImpl: CEDAR MONITOR LOCKS root
IMPORTS IO,
Commander,
LarkRpcControl,
LarkSmartsRpcControl,
Log,
Names,
NamesRPC,
root: LarkSmartsMonitorImpl,
LupineRuntime,
Nice,
RPC,
SafeStorage,
ThNet,
ThPartyPrivate,
ThParty,
Thrush,
ThSmartsPrivate,
ThSmartsRpcControl,
ThVersions,
Triples,
TU
EXPORTS LarkSmarts, ThSmartsPrivate
SHARES LarkSmartsMonitorImpl = {
OPEN IO;
Copies
CallUrgency: TYPE = Thrush.CallUrgency;
CommandEvents: TYPE = Lark.CommandEvents;
ConversationHandle: TYPE = Thrush.ConversationHandle;
H: PROC[r: REF] RETURNS[Thrush.ThHandle] = INLINE {RETURN[Thrush.H[r]]; };
none: SHHH = Thrush.none;
nullHandle: Thrush.ThHandle = Thrush.nullHandle;
PartyHandle: TYPE = Thrush.PartyHandle;
ROPE: TYPE = Thrush.ROPE;
SHHH: TYPE = Lark.SHHH; -- Encrypts conv. if first arg to RPC PROC
RTSmartsType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[ThPartyPrivate.SmartsBody]];
SmartsHandle: TYPE = Thrush.SmartsHandle;
SmartsInfo: TYPE = ThSmartsPrivate.SmartsInfo;
SmartsInfoBody: TYPE = ThSmartsPrivate.SmartsInfoBody;
StatusEvents: TYPE = Lark.StatusEvents;
larkInterfaces: LIST OF LarkRpcControl.InterfaceRecord ← NIL;
larkRegistry: ROPE←".lark";
thSmartsExported: BOOLFALSE;
Registration/Deregistration/Initialization
Register: PUBLIC PROC[
shh: SHHH, -- encrypts connection
oldSmartsID: Thrush.SmartsHandle,
oldEpoch: Thrush.Epoch,
netAddress: Thrush.NetAddress, -- machine name for registering Lark --
model: Lark.LarkModel,
authenticated: BOOLFALSE,
clientInstance: ROPE ]
RETURNS [ smartsID: Thrush.SmartsHandle←nullHandle, epoch: Thrush.Epoch←Thrush.epoch ] = {
larkSh: Lark.SHHH;
partyID: PartyHandle;
localSmarts: ThPartyPrivate.LocalSmartsInterface;
info: SmartsInfo;
larkInterface: LarkRpcControl.InterfaceRecord←NIL;
smarts: ThPartyPrivate.SmartsData;
fullRname: ROPE = RPC.GetCaller[shh];
partyRname: ROPE ← fullRname;
s: Names.Rspec ← NIL;
IF (s←Names.RnameToRspec[partyRname])#NIL
AND Names.RnameToRspec[s.simpleName] # NIL THEN partyRname←s.simpleName;
Above converts from, say, Swinehart.pa.lark to Swinehart.pa.
Also, from Swinehart.pa to Swinehart.pa. Strips one registry if there are two or more.
DO ENABLE UNWIND=>NULL;
Loop is for restart when had to deregister first.
Produce a Party object for this RName, if none exists yet.
partyID ← ThParty.CreateParty[
type: (SELECT model.genre FROM --<<>>-- ENDCASE=> individual),
rName: partyRname];
IF partyID=nullHandle THEN {
Log.ReportFR["Registering party %s not found", $System, NIL, rope[partyRname]];
RETURN[nullHandle, Thrush.epoch];
};
This reregistration should be a no-op, if all of the supplied parameters make sense.
Otherwise, if there is a previous smartsID for this Lark, it must be eliminated.
<< This may all cause trouble later when users log in at Larks -- WAIL.>>
smartsID ← ThPartyPrivate.GetPartySmarts[partyID, $VoiceTerminal];
IF smartsID#nullHandle THEN {
DR: ENTRY PROC = {
ENABLE UNWIND=>NULL;
Deregister[ThSmartsPrivate.GetSmartsInfo[smarts: smarts]];
};
smarts ← ThPartyPrivate.DehandleSmarts[smartsID];
IF oldSmartsID=smartsID AND epoch = Thrush.epoch AND smarts#NIL THEN
WITH smarts.properties SELECT FROM
voiceTerminal, manager =>
IF machine = netAddress THEN RETURN[oldSmartsID, Thrush.epoch];
ENDCASE; -- oldHandle is a strange beast indeed.
IF smarts#NIL THEN DR[];
smartsID←nullHandle; partyID ← nullHandle; LOOP;
};
There are no old Lark Smarts for this Lark. New ones are needed.
Get encryption taken care of
larkSh ← IF NOT ThNet.pd.encryptionRequested THEN Thrush.unencrypted
ELSE NamesRPC.StartConversation [
caller: myName.instance,
callee: fullRname,
key: serverPassword,
level: --<<ECB>>--CBCCheck ! RPC.AuthenticateFailed=> {
Log.ProblemFR["Can't authenticate %g to %g", $System, NIL,
rope[myName.instance], rope[fullRname]]; GOTO NotSmart; }];
Make sure we can talk to the Lark
larkInterface ← LarkRpcControl.ImportNewInterface[
interfaceName: [type: "Lark.Lark", instance: clientInstance] ! RPC.ImportFailed=> {
Log.ProblemFR["Can't import Lark interface from %g", $System, NIL, rope[clientInstance]]; GOTO NotSmart; }];
larkInterfaces ← CONS[larkInterface, larkInterfaces];
<< No way to deal with resumption of calls in progress, as yet. >>
larkInterface.Reset[larkSh, NIL];
localSmarts ← ThSmartsRpcControl.NewInterfaceRecord[];
localSmarts.Progress ← ThSmartsPrivate.LarkProgress;
smartsID←ThPartyPrivate.RegisterLocal[
partyID: partyID,
interface: localSmarts,
properties: [x: voiceTerminal[machine: netAddress]]
];
IF smartsID=nullHandle THEN {Log.ProblemFR["Can't register Lark: %g, %g",$System,NIL,
rope[fullRname], rope[clientInstance]]; GOTO NotSmart; };
No further bad things are expected to happen.
smarts ← ThPartyPrivate.DehandleSmarts[smartsID,TRUE];
info ← NEW[SmartsInfoBody← [
smarts: smarts,
ParseEvent: ThSmartsPrivate.LarkParseEvent,
Supervise: ThSmartsPrivate.LarkSupervise,
larkInfo: NEW[ThSmartsPrivate.LarkInfoBody ← [
interface: larkInterface,
shh: larkSh,
netAddress: netAddress,
model: model]] ]];
info.larkInfo.scratchEv ← NEW[Lark.CommandEventSequence[15]];
Triples.Make[$SmartsData, smarts, info];
info.otherSmarts ← ThPartyPrivate.DehandleSmarts[
ThSmartsPrivate.RegisterTrunk[ partyID, smarts, info ]];
Log.ReportFR[" (%g = %g)", $Smarts, info,
rope[clientInstance], TU.RefAddr[info.smarts]];
EnableSmartsE[info]; -- Ready to go, as long as phone is on hook
EXIT;
REPEAT
NotSmart => RETURN;
ENDLOOP;
};
EnableSmartsE: ENTRY PROC[info: SmartsInfo] = { []𡤎nableSmarts[info]; };
EnableSmarts: PUBLIC INTERNAL PROC[info: SmartsInfo] RETURNS[enabled: BOOL] = {
ENABLE UNWIND, ThSmartsPrivate.LarkFailed =>GOTO Failed;
SELECT info.larkInfo.larkState FROM
none, failed, recovering => NULL;
ENDCASE=> RETURN[TRUE];
IF ThSmartsPrivate.CheckHookState[info.larkInfo].onHook=FALSE THEN RETURN[FALSE];
IF ThParty.Enable[ smartsID: H[info.smarts]]#success THEN RETURN[FALSE]; -- << REPORT!! >> --
IF ThParty.Enable[ smartsID: H[info.otherSmarts]]#success THEN
Log.Problem["Impossible", $Smarts, info];
ThSmartsPrivate.EnterLarkState[ info.larkInfo, none, info ]; -- Clear any previous failure.
ThSmartsPrivate.EnterLarkState[ info.larkInfo, idle, info ]; -- Reset the Lark
RETURN[TRUE];
EXITS
Failed => RETURN[FALSE];
};
Deregister: PUBLIC INTERNAL PROC[info: SmartsInfo] = {
IF info=NIL OR ThPartyPrivate.DehandleSmarts[H[info.smarts]] = NIL THEN RETURN;
ThSmartsPrivate.EnterLarkState[ info.larkInfo, failed, info ]; -- prevent further action.
SimpleDeregister[ThSmartsPrivate.GetSmartsInfo[smarts: info.otherSmarts]];
SimpleDeregister[info];
Unimport the Lark interface (automatic, via finalization.)
Log.ReportFR["Smarts %d (%g) is dead", $Smarts, info,
card[H[info.smarts]], TU.RefAddr[info.smarts]];
};
SimpleDeregister: INTERNAL PROC[info: SmartsInfo] = {
ThParty.Deregister[smartsID: H[info.smarts]];
Triples.Erase[$SmartsData, info.smarts, info];
};
Login: PUBLIC PROC[shh: SHHH, smartsID: SmartsHandle, authenticated: BOOL] = { NULL };
Other Utilities
WhereIsSmartsLog: Log.WhereProc -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM ← NIL] -- = CHECKED {
info: SmartsInfo=NARROW[whereData];
IF info#NIL THEN s←Nice.LarkConLogStream[info.larkInfo.netAddress];
IF s#NIL AND s=Nice.LarkConLogStream[[[0],[0]]] THEN s←NIL; -- use default stream unless debug viewer stream open.
};
WhereIsLarkLog: Log.WhereProc -- [fixedWhereData: REF ANY, whereData: REF ANY] RETURNS [s: STREAM ← NIL] -- = CHECKED {
info: ThSmartsPrivate.LarkInfo=NARROW[whereData];
IF info#NIL THEN s←Nice.LarkConLogStream[info.netAddress];
IF s#NIL AND s=Nice.LarkConLogStream[[[0],[0]]] THEN s←NIL; -- only want the debug viewer stream
};
WhereIsLarkLogFerSherr: Log.WhereProc ← WhereIsLarkLog;
FerSherrDefault: Log.DNFProc=TRUSTED{ RETURN[ThNet.pd.defaultLarkReports]; };
Initialization, export "LarkSmarts"
myName: LarkSmartsRpcControl.InterfaceName;
serverPassword: RPC.EncryptionKey;
LarkSmartsInit: Commander.CommandProc = {
ENABLE {
RPC.ExportFailed => { Log.Problem["LarkSmarts export failed", $System]; GOTO Failed; };
};
myName ← [
type: "LarkSmarts.Lark",
instance: Names.CmdOrToken[cmd: cmd, key: "ThrushServerInstance", default: "Morley.Lark"],
version: ThVersions.ThrushVR];
serverPassword ← Names.CurrentPasskey[Names.CmdOrToken[
cmd: cmd, key: "ThrushServerPassword", default: "MFLFLX"]];
IF thSmartsExported THEN RETURN;
Log.RegisterWhereToReport[proc: WhereIsLarkLog, where: $Lark];
Log.RegisterWhereToReport[proc: WhereIsLarkLogFerSherr, where: $LarkDetailed, defaultIfNotFound: FerSherrDefault];
Same as $Lark, except doesn't print at all if debugging viewer not found.
Log.RegisterWhereToReport[proc: WhereIsSmartsLog, where: $Smarts];
LarkSmartsRpcControl.ExportInterface[
interfaceName: myName,
user: myName.instance,
password: serverPassword];
Log.ReportFR["Export[LarkSmarts.Lark, %s]", $System, NIL, rope[myName.instance]];
thSmartsExported ← TRUE;
EXITS
Failed =>
LarkSmartsRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE];
};
Commander.Register["LarkSmarts", LarkSmartsInit, "LarkSmarts <ExportInstance(opt.) <ServerPassword (opt)>> -- Initialize and Export LarkSmarts"];
}.