Page Numbers: Yes X: 527 Y: 10.5" First Page: 21
Margins: Top: 1" Bottom: .8"
Heading:
Lupine User’s Guide—Version 1.0
Appendix A: Public RPC Interfaces
The following are the public interfaces to Lupine’s RPC runtime, RPC.mesa and MesaRPC.mesa. Small details are likely to have changed since this document was last edited, so remember that Lupine.df always refers to the latest version.
-- RPC.mesa
-- Andrew Birrell
3-Dec-81 10:14:28
-- BZM
29-Oct-81 11:46:31

DIRECTORY
Rope
USING [ROPE],
MesaRPC
USING [AuthenticateFailure, CallFailure, Conversation,
ConversationID, ConversationLevel, EncryptionKey,
EndConversation, ExportFailure, GetLevel, ImportFailure,
GetConversationID, GenerateConversation, matchAllVersions,
maxPrincipalLength, maxShortStringLength, SecurityLevel,
ShortSTRING, unencrypted, VersionRange];

RPC: DEFINITIONS
IMPORTS MesaRPC =
BEGIN


-- Short string/rope/atom types. Used only by Lupine clients.

maxShortStringLength: CARDINAL = MesaRPC.maxShortStringLength;
-- maximum length of ShortSTRING/ShortROPE/ShortATOM values --

ShortSTRING: TYPE = MesaRPC.ShortSTRING;
ShortROPE: TYPE = Rope.ROPE;
ShortATOM: TYPE = ATOM;


-- Types for Import and Export calls.

InterfaceName: TYPE = RECORD [
type: ShortROPE ← NIL, -- e.g., "AlpineAccess.Alpine"
instance: ShortROPE ← NIL, -- e.g., "MontBlanc.Alpine"
version: VersionRange ← matchAllVersions ];

defaultInterfaceName: InterfaceName = [];

VersionRange: TYPE = MesaRPC.VersionRange;

matchAllVersions: VersionRange = MesaRPC.matchAllVersions;


-- Parameter storage zones. Used only by Lupine clients.

Zones: TYPE = RECORD [
gc: ZONE ← NIL,
heap: UNCOUNTED ZONE ← NIL,
mds: MDSZone ← NIL ];

standardZones: Zones = [];

-- Encryption and Authentication facilities.

maxPrincipalLength: CARDINAL = MesaRPC.maxPrincipalLength;
-- Limit on length of ropes used for Principal names --

Principal: TYPE = ShortROPE;

EncryptionKey: TYPE = MesaRPC.EncryptionKey;

MakeKey: PROCEDURE [text: Rope.ROPE] RETURNS[EncryptionKey];

Conversation:
TYPE = MesaRPC.Conversation;

SecurityLevel: TYPE = MesaRPC.SecurityLevel;

ConversationLevel: TYPE = MesaRPC.ConversationLevel;

unencrypted: Conversation = MesaRPC.unencrypted;

GenerateConversation: PROC RETURNS[Conversation] = INLINE
{ RETURN[ MesaRPC.GenerateConversation[] ] };

StartConversation: PROCEDURE[caller: Principal, key: EncryptionKey,
callee: Principal,
level: ConversationLevel ]
RETURNS[conversation: Conversation];

EndConversation: PROCEDURE [conversation: Conversation] = INLINE
{ MesaRPC.EndConversation[conversation] };

GetCaller: PROCEDURE [conversation: Conversation]
RETURNS [caller: Principal];

GetLevel: PROCEDURE [conversation: Conversation]
RETURNS [level: SecurityLevel] = INLINE
{ RETURN[ MesaRPC.GetLevel[conversation] ] };

ConversationID: TYPE = MesaRPC.ConversationID;

GetConversationID: PROC[conversation: Conversation]
RETURNS[id: ConversationID] = INLINE
{ RETURN[ MesaRPC.GetConversationID[conversation] ] };


-- Public signals:

AuthenticateFailure: TYPE = MesaRPC.AuthenticateFailure;

ExportFailure: TYPE = MesaRPC.ExportFailure;

ImportFailure: TYPE = MesaRPC.ImportFailure;

CallFailure: TYPE = MesaRPC.CallFailure;

AuthenticateFailed: ERROR[why: AuthenticateFailure];
-- Raised by StartConversation --

ExportFailed: ERROR[why: ExportFailure];
-- Raised by ExportInterface --

ImportFailed: ERROR[why: ImportFailure];
-- Raised by ImportInterface --

CallFailed: SIGNAL[why: CallFailure];
-- Raised by any remote call; only why=timeout is resumable --

END.
-- MesaRPC.mesa
-- Andrew Birrell
3-Dec-81 10:12:00
-- BZM
29-Oct-81 11:45:47

DIRECTORY
BodyDefs
USING[ maxRNameLength, Password ];

MesaRPC: DEFINITIONS =

BEGIN


-- Short string types. Used only by Lupine clients.

maxShortStringLength: CARDINAL = 64;
-- Maximum length of ShortSTRING values. --

ShortSTRING: TYPE = STRING;


-- Types for Import/Export calls --

InterfaceName: TYPE = RECORD [
type: LONG ShortSTRING ← NIL, -- e.g. "AlpineAccess.Alpine" --
instance: LONG ShortSTRING ← NIL, -- e.g. "MontBlanc.Alpine" --
version: VersionRange ← matchAllVersions];

defaultInterfaceName: InterfaceName = [];

VersionRange: TYPE = MACHINE DEPENDENT RECORD[first, last: CARDINAL];
-- client-defined, closed interval --

matchAllVersions: VersionRange = [1,0];
-- importer: use any version; exporter: no versioning implied --



-- Parameter storage zones. Used only by Lupine clients, not the runtime.

Zones: TYPE = RECORD [
heap: UNCOUNTED ZONE ← NIL,
mds: MDSZone ← NIL ];

standardZones: Zones = [];

-- Encryption and Authentication facilities --

maxPrincipalLength: CARDINAL = MIN[maxShortStringLength,
BodyDefs.maxRNameLength];
-- Limit on length of strings used for Principal --

Principal:
TYPE = LONG ShortSTRING;
-- Name of authentication principal --

EncryptionKey: TYPE = BodyDefs.Password;
-- DES key --

MakeKey: PROC[text: LONG STRING] RETURNS[EncryptionKey];

Conversation:
TYPE = LONG POINTER TO ConversationObject;

ConversationObject: PRIVATE TYPE;

SecurityLevel: TYPE = MACHINE DEPENDENT {
none(0),
-- unauthenticated, insecure; used for "unencrypted"
authOnly(1),
-- authenticated, but unencrypted calls
ECB(2),
-- authenticated, encrypt with ECB mode of DES
CBC(3),
-- authenticated, encrypt with CBC mode of DES
CBCCheck(4)
-- authenticated, encrypt with CBC mode of DES + checksum
};

ConversationLevel: TYPE = SecurityLevel[authOnly..CBCCheck];

unencrypted:
Conversation = NIL;
-- Dummy conversation; may be passed to RPC runtime.
-- GetConversationID[unencrypted] = ERROR;
-- GetCaller[unencrypted] = NIL;
-- GetLevel[unencrypted] = none; --

GenerateConversation: PROC RETURNS[Conversation];
-- Returns a handle for a previously unused Conversation. This
-- conversation is only for local use, it must not be passed to
-- the RPC runtime.
-- GetConversationID[GenerateConversation[]] = unique ID;
-- GetCaller[GenerateConversation[]] = NIL;
-- GetLevel[GenerateConversation[]] = "none"; --

StartConversation: PROC[caller: Principal, key: EncryptionKey,
callee: Principal,
level: ConversationLevel]
RETURNS[conversation: Conversation];
-- Obtains authenticator for conversation, registers it with runtime,
-- and allocates ConversationID --

EndConversation: PROC[conversation: Conversation];
-- Terminates use of this conversation --

GetCaller:
PROC[conversation: Conversation]
RETURNS[caller: Principal];
-- Returns the caller name for a current call. The result
-- string has lifetime at least equal to the duration of the
-- call. Result is NIL if conversation’s security level is "none" (including
-- conversation = "unencrypted"). --

GetLevel:
PROC[conversation: Conversation]
RETURNS[level: SecurityLevel];

ConversationID: TYPE[3];
-- UID allocated by initiator host --

GetConversationID: PROC[conversation: Conversation]
RETURNS[id: ConversationID];
-- Returns permanently unique ID of this conversation --



-- Public signals --

AuthenticateFailure: TYPE = {
communications,-- couldn’t contact authentication server(s) --
badCaller,-- invalid caller name --
badKey,-- incorrect caller password --
badCallee-- invalid callee name --
};

ExportFailure: TYPE = {
communications, -- couldn’t access binding database --
badType,-- unacceptable interface type name --
badInstance,-- unacceptable interface instance name --
badVersion,-- statically silly version range --
tooMany,-- too many exports for local tables --
badCredentials-- not allowed to change the database --
};

ImportFailure: TYPE = {
communications, -- couldn’t access binding database --
badType,-- unacceptable interface type name --
badInstance,-- unacceptable interface instance name --
badVersion,-- statically silly version range --
wrongVersion,-- exported version not in req’d range --
unbound,-- this instance not exported --
stubProtocol-- exporter protocol incompatible with importer --
};

CallFailure:
TYPE = {
timeout,-- no acknowledgement within reasonable time --
unbound,-- server no longer exports the interface --
busy,-- server says it’s too busy --
runtimeProtocol,-- user/server runtimes don’t understand each other --
stubProtocol-- user/server stubs don’t understand each other --
};

AuthenticateFailed: ERROR[why: AuthenticateFailure];
-- Raised by StartConversation --

ExportFailed: ERROR[why: ExportFailure];
-- Raised by ExportInterface --

ImportFailed: ERROR[why: ImportFailure];
-- Raised by ImportInterface --

CallFailed: SIGNAL[why: CallFailure];
-- Raised by any remote call; only why=timeout is resumable --

END.
Appendix B: Example Remote Interface and Stubs
There follows a very simple interface, Target.mesa, and its stub modules as an example. Once again, small details may have changed, but this is unimportant since RPC programmers need not be concerned with stub implementations. These modules are un-retouched output from the Lupine translator.
-- Lupine: example interface
-- Target.mesa
-- Andrew Birrell July 8, 1982 9:22 am

DIRECTORY
Rope
USING[ ROPE ];

Target: DEFINITIONS =

BEGIN

Basic: PROC;

Simple: PROC[first: INT, second: REF INT] RETURNS[a: Rope.ROPE, b: ATOM];

Reason: TYPE = { x, y, z };

Exception: ERROR[why: Reason];

Consultation: SIGNAL;

END.
-- Stub file TargetRpcControl.mesa was translated on 8-Jul-82 9:59:49
-- PDT by Lupine of 7-Jul-82 17:14:26 PDT.

-- Source interface Target came from file Target.bcd, which was created
-- on 8-Jul-82 9:59:46 PDT with version stamp 52#64#37310473537 from
-- source of 8-Jul-82 9:33:34 PDT.

-- The RPC stub modules for Target are:
-- TargetRpcControl.mesa;
-- TargetRpcClientImpl.mesa;
-- TargetRpcBinderImpl.mesa;
-- TargetRpcServerImpl.mesa.

-- The parameters for this translation are:
-- Target language = Cedar;
-- Default parameter passing = VALUE;
-- Deallocate server heap arguments = TRUE;
-- Inline RpcServerImpl dispatcher stubs = TRUE;
-- Maximum number of dynamic heap NEWs = 50, MDS NEWs = 50;
-- Acceptable parameter protocols = VersionRange[1,1].


DIRECTORY
Rope,
Target,
RPC USING [defaultInterfaceName, EncryptionKey, InterfaceName, Principal,
standardZones, VersionRange, Zones];


TargetRpcControl: DEFINITIONS
SHARES Target
= BEGIN OPEN Target, RpcPublic: RPC;


-- Public RPC types and constants.

InterfaceName: TYPE = RpcPublic.InterfaceName;
VersionRange: TYPE = RpcPublic.VersionRange;
Principal: TYPE = RpcPublic.Principal;
EncryptionKey: TYPE = RpcPublic.EncryptionKey;
Zones: TYPE = RpcPublic.Zones;

defaultInterfaceName: InterfaceName = RpcPublic.defaultInterfaceName;
standardZones: Zones = RpcPublic.standardZones;


-- Standard remote binding routines.

ImportInterface: SAFE PROCEDURE [
interfaceName: InterfaceName ← defaultInterfaceName,
parameterStorage: Zones ← standardZones ];

UnimportInterface: SAFE PROCEDURE;

ExportInterface: SAFE PROCEDURE [
interfaceName: InterfaceName ← defaultInterfaceName,
user: Principal,
password: EncryptionKey,
parameterStorage: Zones ← standardZones ];

UnexportInterface: SAFE PROCEDURE;


-- Dynamic instantiation and binding.

ImportNewInterface: SAFE PROCEDURE [
interfaceName: InterfaceName ← defaultInterfaceName,
parameterStorage: Zones ← standardZones ]
RETURNS [interfaceRecord: InterfaceRecord];

InterfaceRecord: TYPE = REF InterfaceRecordObject;

InterfaceRecordObject: TYPE = RECORD [
Basic: PROCEDURE,
Simple: PROCEDURE [first: INT, second: REF INT] RETURNS [a: Rope.ROPE,
b: ATOM],
Exception: ERROR [why: Reason],
Consultation: SIGNAL,
lupineDetails: PRIVATE REF LupineDetailsObject←NIL];

LupineDetailsObject: PRIVATE TYPE;


-- Definitions for the stubs.

LupineProtocolVersion: PUBLIC VersionRange = [first: 1, last: 1];

InterMdsCallsOnly: PUBLIC BOOLEAN = FALSE;

ProcedureIndex: PRIVATE TYPE = MACHINE DEPENDENT {
LupineUnusedIndex (0), LupineLastIndex (3),
Basic (4), Simple (5)};

SignalIndex: PRIVATE TYPE = MACHINE DEPENDENT {
LupineUnusedIndex (0), LupineLastIndex (3),
Exception (4), Consultation (5)};


END. -- TargetRpcControl.
-- Stub file TargetRpcClientImpl.mesa was translated on 8-Jul-82
-- 9:59:50 PDT by Lupine of 7-Jul-82 17:14:26 PDT.

-- Source interface Target came from file Target.bcd, which was created
-- on 8-Jul-82 9:59:46 PDT with version stamp 52#64#37310473537 from
-- source of 8-Jul-82 9:33:34 PDT.

-- The RPC stub modules for Target are:
-- TargetRpcControl.mesa;
-- TargetRpcClientImpl.mesa;
-- TargetRpcBinderImpl.mesa;
-- TargetRpcServerImpl.mesa.

-- The parameters for this translation are:
-- Target language = Cedar;
-- Default parameter passing = VALUE;
-- Deallocate server heap arguments = TRUE;
-- Inline RpcServerImpl dispatcher stubs = TRUE;
-- Maximum number of dynamic heap NEWs = 50, MDS NEWs = 50;
-- Acceptable parameter protocols = VersionRange[1,1].


DIRECTORY
Rope,
Target,
TargetRpcControl USING [InterMdsCallsOnly, LupineProtocolVersion,
ProcedureIndex, SignalIndex],
RPC USING [InterfaceName, standardZones, Zones],
RPCLupine --USING SOME OF [Call, DataLength, Dispatcher, GetStubPkt,
-- ImportHandle, ImportInterface, maxDataLength, maxPrincipalLength,
-- maxShortStringLength, pktOverhead, ReceiveExtraPkt, SendPrelimPkt,
-- StartCall, StartSignal, StubPkt, UnimportInterface]--,
LupineRuntime --USING SOME OF [BindingError, CheckPktLength, CopyFromPkt,
-- CopyFromMultiplePkts, CopyToPkt, CopyToMultiplePkts, DispatchingError,
-- FinishThisPkt, ListHeader, MarshalingError, MarshalingExprError,
-- NilHeader, ProtocolError, RopeHeader, RpcPktDoubleWord, RuntimeError,
-- SequenceHeader, SHORT, StartNextPkt, StringHeader, StubPktDoubleWord,
-- TranslationError, UnmarshalingError, UnmarshalingExprError, WordsForChars]--,
Atom --USING SOME OF [GetPName, MakeAtom]--,
ConvertUnsafe USING [AppendRope],
Heap USING [systemMDSZone],
RopeInline --USING SOME OF [InlineFlatten, NewText]--,
SafeStorage USING [GetSystemZone],
UnsafeStorage USING [GetSystemUZone];


TargetRpcClientImpl: MONITOR
IMPORTS RpcPrivate: RPCLupine, Lupine: LupineRuntime, Atom, ConvertUnsafe,
Heap, RopeInline, SafeStorage, UnsafeStorage
EXPORTS Target, TargetRpcControl
SHARES Target, TargetRpcControl, Rope
= BEGIN OPEN Target, RpcControl: TargetRpcControl, RpcPublic: RPC;


-- Standard remote binding routines.

bound: BOOLEAN ← FALSE;
myInterface: RpcPrivate.ImportHandle ← NULL;
paramZones: RpcPublic.Zones ← RpcPublic.standardZones;

ImportInterface: PUBLIC ENTRY SAFE PROCEDURE [
interfaceName: RpcPublic.InterfaceName,
parameterStorage: RpcPublic.Zones ] =
TRUSTED BEGIN ENABLE UNWIND => NULL;
IsNull: PROCEDURE [string: LONG STRING] RETURNS [BOOLEAN] =
INLINE {RETURN[ string=NIL OR string.length=0 ]};
IF bound THEN Lupine.BindingError;
BEGIN
type: STRING = [RpcPrivate.maxShortStringLength];
instance: STRING = [RpcPrivate.maxShortStringLength];
ConvertUnsafe.AppendRope[to: type, from: interfaceName.type];
ConvertUnsafe.AppendRope[to: instance, from: interfaceName.instance];
myInterface ← RpcPrivate.ImportInterface [
interface: [
type: IF ~IsNull[type]
THEN type ELSE "Target~52#64#37310473537"L,
instance: instance,
version: interfaceName.version ],
localOnly: RpcControl.InterMdsCallsOnly,
stubProtocol: RpcControl.LupineProtocolVersion ];
END;
paramZones ← [
gc: IF parameterStorage.gc # NIL
THEN parameterStorage.gc ELSE SafeStorage.GetSystemZone[],
heap: IF parameterStorage.heap # NIL
THEN parameterStorage.heap ELSE UnsafeStorage.GetSystemUZone[],
mds: IF parameterStorage.mds # NIL
THEN parameterStorage.mds ELSE Heap.systemMDSZone ];
bound ← TRUE;
END;

UnimportInterface: PUBLIC ENTRY SAFE PROCEDURE =
TRUSTED BEGIN ENABLE UNWIND => NULL;
IF ~bound THEN Lupine.BindingError;
myInterface ← RpcPrivate.UnimportInterface[myInterface];
paramZones ← RpcPublic.standardZones;
bound ← FALSE;
END;


-- Remote public procedure stubs.

Basic: PUBLIC PROCEDURE =
BEGIN
ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
transferIndex (0): RpcControl.ProcedureIndex ← Basic];
pktBuffer: ARRAY [1..RpcPrivate.pktOverhead+1] OF WORD;
pkt: RpcPrivate.StubPkt = RpcPrivate.GetStubPkt[space: @pktBuffer];
argPkt: POINTER TO ArgumentOverlay = @pkt.data[0];
pktLength: RpcPrivate.DataLength ← 1;
lastPkt: BOOLEAN;
RpcPrivate.StartCall[callPkt: pkt, interface: myInterface];
argPkt.transferIndex ← Basic;
[returnLength: , lastPkt: lastPkt] ←
RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
maxReturnLength: 0, signalHandler: ClientDispatcher];
Lupine.CheckPktLength[pkt: pkt, pktLength: 0];
RETURN[];
END; -- Basic.

Simple: PUBLIC PROCEDURE [first: INT, second: REF INT] RETURNS [a:
Rope.ROPE, b: ATOM] =
BEGIN
ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
transferIndex (0): RpcControl.ProcedureIndex ← Simple, first (1):
INT];
pktBuffer: ARRAY [1..RpcPrivate.pktOverhead+254] OF WORD;
pkt: RpcPrivate.StubPkt = RpcPrivate.GetStubPkt[space: @pktBuffer];
argPkt: POINTER TO ArgumentOverlay = @pkt.data[0];
pktLength: RpcPrivate.DataLength ← 3;
lastPkt: BOOLEAN;
RpcPrivate.StartCall[callPkt: pkt, interface: myInterface];
argPkt↑ ← [first: first];
BEGIN -- Marshal second: REF INT to pkt.data[pktLength].
pkt.data[pktLength] ← second=NIL; pktLength ← pktLength+1;
IF second # NIL THEN
BEGIN
Lupine.StubPktDoubleWord[pkt, pktLength]↑ ← second↑;
pktLength ← pktLength + 2;
END;
END; -- Marshal second.
[returnLength: , lastPkt: lastPkt] ←
RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
maxReturnLength: 254, signalHandler: ClientDispatcher];
pktLength ← 0;
BEGIN -- Unmarshal a: Rope.ROPE from pkt.data[pktLength].
ropeIsNIL: Lupine.NilHeader;
IF pktLength+2 > RpcPrivate.maxDataLength
THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
pktLength];
ropeIsNIL ← pkt.data[pktLength]; pktLength ← pktLength+1;
IF ropeIsNIL
THEN a ← NIL
ELSE BEGIN
ropeLength: Lupine.RopeHeader;
textRope: Rope.Text;
ropeLength ← pkt.data[pktLength]; pktLength ← pktLength+1;
IF ropeLength > LAST[NAT]
THEN Lupine.UnmarshalingError;
a ← textRope ← RopeInline.NewText[size: ropeLength];
pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[ropeLength],
alwaysOnePkt: FALSE];
END; -- IF ropeIsNIL.
END; -- Unmarshal a.
BEGIN -- Unmarshal b: ATOM from pkt.data[pktLength].
pNameOfAtom: Rope.ROPE;
ropeIsNIL: Lupine.NilHeader;
IF pktLength+2 > RpcPrivate.maxDataLength
THEN pktLength ← Lupine.FinishThisPkt[pkt: pkt, pktLength:
pktLength];
ropeIsNIL ← pkt.data[pktLength]; pktLength ← pktLength+1;
IF ropeIsNIL
THEN pNameOfAtom ← NIL
ELSE BEGIN
ropeLength: Lupine.RopeHeader;
textRope: Rope.Text;
ropeLength ← pkt.data[pktLength]; pktLength ← pktLength+1;
IF ropeLength > LAST[NAT]
THEN Lupine.UnmarshalingError;
pNameOfAtom ← textRope ← RopeInline.NewText[size: ropeLength];
pktLength ← Lupine.CopyFromPkt[pkt: pkt, pktLength: pktLength,
dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[ropeLength],
alwaysOnePkt: FALSE];
END; -- IF ropeIsNIL.
b ← Atom.MakeAtom[--pName:-- pNameOfAtom];
END; -- Unmarshal b.
Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
RETURN[a, b];
END; -- Simple.


-- Remote public signals and errors.

Exception: PUBLIC ERROR [why: Reason] = CODE;

Consultation: PUBLIC SIGNAL = CODE;


-- Public signal and error dispatcher.

ClientDispatcher: --PROCEDURE [pkt: RPCPkt, callLength: DataLength,
-- lastPkt: BOOLEAN, localConversation: Conversation] RETURNS [returnLength:
-- DataLength]-- RpcPrivate.Dispatcher =
BEGIN

SELECT LOOPHOLE[pkt.data[0], RpcControl.SignalIndex] FROM
Exception => RETURN[
ExceptionStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
localConversation: localConversation]];
Consultation => RETURN[
ConsultationStub[pkt: pkt, callLength: callLength, lastPkt:
lastPkt, localConversation: localConversation]];
ENDCASE => RETURN[Lupine.DispatchingError[]];

END; -- ClientDispatcher


-- Public signal and error dispatcher stubs.

ExceptionStub: --ERROR [why: Reason]-- RpcPrivate.Dispatcher =
INLINE BEGIN
ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
transferIndex (0): RpcControl.SignalIndex, why (1): Reason];
argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
Lupine.CheckPktLength[pkt: pkt, pktLength: 2];
ERROR Exception[argPkt.why];
END; -- ExceptionStub.

ConsultationStub: --SIGNAL-- RpcPrivate.Dispatcher =
INLINE BEGIN
pktLength: RpcPrivate.DataLength;
Lupine.CheckPktLength[pkt: pkt, pktLength: 1];
SIGNAL Consultation[];
pktLength ← 0;
RETURN[returnLength: pktLength];
END; -- ConsultationStub.


-- No module initialization.

END. -- TargetRpcClientImpl.
-- Stub file TargetRpcServerImpl.mesa was translated on 8-Jul-82
-- 9:59:52 PDT by Lupine of 7-Jul-82 17:14:26 PDT.

-- Source interface Target came from file Target.bcd, which was created
-- on 8-Jul-82 9:59:46 PDT with version stamp 52#64#37310473537 from
-- source of 8-Jul-82 9:33:34 PDT.

-- The RPC stub modules for Target are:
-- TargetRpcControl.mesa;
-- TargetRpcClientImpl.mesa;
-- TargetRpcBinderImpl.mesa;
-- TargetRpcServerImpl.mesa.

-- The parameters for this translation are:
-- Target language = Cedar;
-- Default parameter passing = VALUE;
-- Deallocate server heap arguments = TRUE;
-- Inline RpcServerImpl dispatcher stubs = TRUE;
-- Maximum number of dynamic heap NEWs = 50, MDS NEWs = 50;
-- Acceptable parameter protocols = VersionRange[1,1].


DIRECTORY
Rope,
Target,
TargetRpcControl USING [InterMdsCallsOnly, LupineProtocolVersion,
ProcedureIndex, SignalIndex],
RPC USING [EncryptionKey, InterfaceName, Principal, standardZones,
Zones],
RPCLupine --USING SOME OF [Call, DataLength, Dispatcher, ExportHandle,
-- ExportInterface, GetStubPkt, maxDataLength, maxPrincipalLength,
-- maxShortStringLength, pktOverhead, ReceiveExtraPkt, SendPrelimPkt,
-- StartCall, StartSignal, StubPkt, UnexportInterface]--,
LupineRuntime --USING SOME OF [BindingError, CheckPktLength, CopyFromPkt,
-- CopyFromMultiplePkts, CopyToPkt, CopyToMultiplePkts, DispatchingError,
-- FinishThisPkt, ListHeader, MarshalingError, MarshalingExprError,
-- NilHeader, ProtocolError, RopeHeader, RpcPktDoubleWord, RuntimeError,
-- SequenceHeader, SHORT, StartNextPkt, StringHeader, StubPktDoubleWord,
-- TranslationError, UnmarshalingError, UnmarshalingExprError, WordsForChars]--,
Atom --USING SOME OF [GetPName, MakeAtom]--,
ConvertUnsafe USING [AppendRope],
Heap USING [systemMDSZone],
RopeInline --USING SOME OF [InlineFlatten, NewText]--,
SafeStorage USING [GetSystemZone],
UnsafeStorage USING [GetSystemUZone];


TargetRpcServerImpl: MONITOR
IMPORTS Target, RpcPrivate: RPCLupine, Lupine: LupineRuntime, Atom,
ConvertUnsafe, Heap, RopeInline, SafeStorage, UnsafeStorage
EXPORTS TargetRpcControl
SHARES Target, TargetRpcControl, Rope
= BEGIN OPEN Target, RpcControl: TargetRpcControl, RpcPublic: RPC;


-- Standard remote binding routines.

bound: BOOLEAN ← FALSE;
myInterface: RpcPrivate.ExportHandle ← NULL;
paramZones: RpcPublic.Zones ← RpcPublic.standardZones;

ExportInterface: PUBLIC ENTRY SAFE PROCEDURE [
interfaceName: RpcPublic.InterfaceName,
user: RpcPublic.Principal,
password: RpcPublic.EncryptionKey,
parameterStorage: RpcPublic.Zones ] =
TRUSTED BEGIN ENABLE UNWIND => NULL;
IsNull: PROCEDURE [string: LONG STRING] RETURNS [BOOLEAN] =
INLINE {RETURN[ string=NIL OR string.length=0 ]};
IF bound THEN Lupine.BindingError;
BEGIN
type: STRING = [RpcPrivate.maxShortStringLength];
instance: STRING = [RpcPrivate.maxShortStringLength];
userString: STRING = [RpcPrivate.maxPrincipalLength];
ConvertUnsafe.AppendRope[to: type, from: interfaceName.type];
ConvertUnsafe.AppendRope[to: instance, from: interfaceName.instance];
ConvertUnsafe.AppendRope[to: userString, from: user];
myInterface ← RpcPrivate.ExportInterface [
interface: [
type: IF ~IsNull[type]
THEN type ELSE "Target~52#64#37310473537"L,
instance: instance,
version: interfaceName.version ],
user: userString, password: password,
dispatcher: ServerDispatcher,
localOnly: RpcControl.InterMdsCallsOnly,
stubProtocol: RpcControl.LupineProtocolVersion ];
END;
paramZones ← [
gc: IF parameterStorage.gc # NIL
THEN parameterStorage.gc ELSE SafeStorage.GetSystemZone[],
heap: IF parameterStorage.heap # NIL
THEN parameterStorage.heap ELSE UnsafeStorage.GetSystemUZone[],
mds: IF parameterStorage.mds # NIL
THEN parameterStorage.mds ELSE Heap.systemMDSZone ];
bound ← TRUE;
END;

UnexportInterface: PUBLIC ENTRY SAFE PROCEDURE =
TRUSTED BEGIN ENABLE UNWIND => NULL;
IF ~bound THEN Lupine.BindingError;
myInterface ← RpcPrivate.UnexportInterface[myInterface];
paramZones ← RpcPublic.standardZones;
bound ← FALSE;
END;


-- Public procedure dispatcher and public signal and error catcher.

ServerDispatcher: --PROCEDURE [pkt: RPCPkt, callLength: DataLength,
-- lastPkt: BOOLEAN, localConversation: Conversation] RETURNS [returnLength:
-- DataLength]-- RpcPrivate.Dispatcher =
BEGIN

-- Catch public signals.

ENABLE BEGIN

Exception --ERROR [why: Reason]-- =>
BEGIN
ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
transferIndex (0): RpcControl.SignalIndex ← Exception, why
(1): Reason];
argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
pktLength: RpcPrivate.DataLength ← 2;
lastPkt: BOOLEAN;
RpcPrivate.StartSignal[signalPkt: pkt];
argPkt↑ ← [why: why];
[returnLength: , lastPkt: lastPkt] ←
RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
maxReturnLength: 0];
Lupine.RuntimeError; -- Impossible to RESUME an ERROR.
END; -- Exception.

Consultation --SIGNAL-- =>
BEGIN
ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
transferIndex (0): RpcControl.SignalIndex ← Consultation];
argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
pktLength: RpcPrivate.DataLength ← 1;
lastPkt: BOOLEAN;
RpcPrivate.StartSignal[signalPkt: pkt];
argPkt.transferIndex ← Consultation;
[returnLength: , lastPkt: lastPkt] ←
RpcPrivate.Call[ pkt: pkt, callLength: pktLength,
maxReturnLength: 0];
Lupine.CheckPktLength[pkt: pkt, pktLength: 0];
RESUME[];
END; -- Consultation.

END; -- Catch public signals.


-- Call public procedures (still in dispatcher).

SELECT LOOPHOLE[pkt.data[0], RpcControl.ProcedureIndex] FROM
Basic => RETURN[
BasicStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
localConversation: localConversation]];
Simple => RETURN[
SimpleStub[pkt: pkt, callLength: callLength, lastPkt: lastPkt,
localConversation: localConversation]];
ENDCASE => RETURN[Lupine.DispatchingError[]];

END; -- ServerDispatcher


-- Public procedure dispatcher stubs.

BasicStub: --PROCEDURE-- RpcPrivate.Dispatcher =
INLINE BEGIN
pktLength: RpcPrivate.DataLength;
Lupine.CheckPktLength[pkt: pkt, pktLength: 1];
Basic[];
pktLength ← 0;
RETURN[returnLength: pktLength];
END; -- BasicStub.

SimpleStub: --PROCEDURE [first: INT, second: REF INT] RETURNS [a:
-- Rope.ROPE, b: ATOM]-- RpcPrivate.Dispatcher =
INLINE BEGIN
second: REF INT;
a: Rope.ROPE;
b: ATOM;
ArgumentOverlay: TYPE = MACHINE DEPENDENT RECORD [
transferIndex (0): RpcControl.ProcedureIndex, first (1): INT];
argPkt: LONG POINTER TO ArgumentOverlay = @pkt.data[0];
pktLength: RpcPrivate.DataLength ← 3;
BEGIN -- Unmarshal second: REF INT from pkt.data[pktLength].
isNIL: Lupine.NilHeader;
isNIL ← pkt.data[pktLength]; pktLength ← pktLength+1;
IF isNIL
THEN second ← NIL
ELSE BEGIN
second ← (paramZones.gc.NEW[INT]);
BEGIN
second↑ ← Lupine.RpcPktDoubleWord[pkt, pktLength]↑;
pktLength ← pktLength + 2;
END;
END; -- IF isNIL.
END; -- Unmarshal second.
Lupine.CheckPktLength[pkt: pkt, pktLength: pktLength];
[a, b] ←
Simple[argPkt.first, second];
pktLength ← 0;
BEGIN -- Marshal a: Rope.ROPE to pkt.data[pktLength].
IF pktLength+2 > RpcPrivate.maxDataLength
THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength: pktLength];
pkt.data[pktLength] ← a=NIL; pktLength ← pktLength+1;
IF a # NIL
THEN BEGIN
textRope: Rope.Text = RopeInline.InlineFlatten[r: a];
pkt.data[pktLength] ← textRope.length; pktLength ← pktLength+1;
pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[textRope.length],
alwaysOnePkt: FALSE];
END; -- IF a # NIL.
END; -- Marshal a.
BEGIN -- Marshal b: ATOM to pkt.data[pktLength].
pNameOfAtom: Rope.Text = Atom.GetPName[atom: b];
IF pktLength+2 > RpcPrivate.maxDataLength
THEN pktLength ← Lupine.StartNextPkt[pkt: pkt, pktLength: pktLength];
pkt.data[pktLength] ← pNameOfAtom=NIL; pktLength ← pktLength+1;
IF pNameOfAtom # NIL
THEN BEGIN
textRope: Rope.Text = RopeInline.InlineFlatten[r: pNameOfAtom];
pkt.data[pktLength] ← textRope.length; pktLength ← pktLength+1;
pktLength ← Lupine.CopyToPkt[pkt: pkt, pktLength: pktLength,
dataAdr: BASE[DESCRIPTOR[textRope.text]], dataLength: Lupine.WordsForChars[textRope.length],
alwaysOnePkt: FALSE];
END; -- IF pNameOfAtom # NIL.
END; -- Marshal b.
RETURN[returnLength: pktLength];
END; -- SimpleStub.


-- No module initialization.

END. -- TargetRpcServerImpl.
-- Stub file TargetRpcBinderImpl.mesa was translated on 8-Jul-82
-- 9:59:51 PDT by Lupine of 7-Jul-82 17:14:26 PDT.

-- Source interface Target came from file Target.bcd, which was created
-- on 8-Jul-82 9:59:46 PDT with version stamp 52#64#37310473537 from
-- source of 8-Jul-82 9:33:34 PDT.

-- The RPC stub modules for Target are:
-- TargetRpcControl.mesa;
-- TargetRpcClientImpl.mesa;
-- TargetRpcBinderImpl.mesa;
-- TargetRpcServerImpl.mesa.

-- The parameters for this translation are:
-- Target language = Cedar;
-- Default parameter passing = VALUE;
-- Deallocate server heap arguments = TRUE;
-- Inline RpcServerImpl dispatcher stubs = TRUE;
-- Maximum number of dynamic heap NEWs = 50, MDS NEWs = 50;
-- Acceptable parameter protocols = VersionRange[1,1].

-- NOTE: Discard this module unless you use dynamic client binding.


DIRECTORY
TargetRpcControl USING [InterfaceRecord, InterfaceRecordObject],
TargetRpcClientImpl,
RPC USING [InterfaceName, Zones],
RTTypesBasic USING [EstablishFinalization, FinalizationQueue, FQEmpty,
FQNext, NewFQ];


TargetRpcBinderImpl: MONITOR
IMPORTS ClientPrototype: TargetRpcClientImpl, RTT: RTTypesBasic
EXPORTS TargetRpcControl
SHARES TargetRpcControl
= BEGIN OPEN RpcControl: TargetRpcControl, RpcPublic: RPC;


-- Dynamic instantiation and binding routines.

ImportNewInterface: PUBLIC SAFE PROCEDURE [
interfaceName: RpcPublic.InterfaceName,
parameterStorage: RpcPublic.Zones ]
RETURNS [interfaceRecord: RpcControl.InterfaceRecord] =
TRUSTED BEGIN
interfaceRecord ← NewInterface[];
LupineDetails[interfaceRecord].module.ImportInterface [
interfaceName: interfaceName,
parameterStorage: parameterStorage
! UNWIND => FreeInterface[interfaceRecord] ];
END;

UnimportNewInterface: SAFE PROCEDURE [
interfaceRecord: RpcControl.InterfaceRecord ] =
TRUSTED BEGIN
LupineDetails[interfaceRecord].module.UnimportInterface[];
FreeInterface[interfaceRecord];
END;


-- Utility routines for interface instantiation and caching.

ConcreteLupineDetails: TYPE = REF LupineDetailsObject;

LupineDetailsObject: PUBLIC TYPE = RECORD [
module: ClientModule←NIL,
next: RpcControl.InterfaceRecord←NIL,
self: RpcControl.InterfaceRecord←NIL ];

LupineDetails: PROCEDURE [abstractInterface: RpcControl.InterfaceRecord]
RETURNS [ConcreteLupineDetails] =
INLINE {RETURN[abstractInterface.lupineDetails]};

ClientModule: TYPE = POINTER TO FRAME[TargetRpcClientImpl];


clientInterfaceCache: RpcControl.InterfaceRecord ← NIL;

NewInterface: PROCEDURE RETURNS [interface: RpcControl.InterfaceRecord]=
BEGIN
GetCachedInterface: ENTRY PROCEDURE
RETURNS [cachedIR: RpcControl.InterfaceRecord] =
INLINE BEGIN ENABLE UNWIND => NULL;
IF (cachedIR←clientInterfaceCache) # NIL
THEN clientInterfaceCache ← LupineDetails[clientInterfaceCache].next;
END;
ReclaimInterfaces;
IF (interface ← GetCachedInterface[]) = NIL
THEN BEGIN
module: ClientModule = NEW ClientPrototype;
interface ← NEW[
RpcControl.InterfaceRecordObject ← [
Basic: module.Basic, Simple: module.Simple, Exception: module.Exception,
Consultation: module.Consultation]];
interface.lupineDetails ← NEW[
LupineDetailsObject ← [module: module, self: interface]];
END;
END;

FreeInterface: ENTRY PROCEDURE [interface: RpcControl.InterfaceRecord]=
INLINE BEGIN ENABLE UNWIND => NULL;
LupineDetails[interface].next ← clientInterfaceCache;
clientInterfaceCache ← interface;
END;


-- Finalization for dynamic interfaces. Just cache and reuse for now.

freedInterfaces: RTT.FinalizationQueue = RTT.NewFQ[20];

ReclaimInterfaces: PROCEDURE =
INLINE BEGIN
WHILE ~RTT.FQEmpty[freedInterfaces] DO
UnimportNewInterface[
interfaceRecord: NARROW[RTT.FQNext[freedInterfaces]] ];
ENDLOOP;
END;


-- Module initialization.

RTT.EstablishFinalization[
type: CODE[RpcControl.InterfaceRecordObject],
npr: 1, fq: freedInterfaces ];


END. -- TargetRpcBinderImpl.