-- RPC: Interface between stubs and runtime.
-- [Ivy]<Birrell>RPC>RPCLupine.mesa
-- Bruce Nelson 6 Oct. 1981 9:44 am PDT (Tuesday)
-- Andrew Birrell 16-Mar-82 14:09:17
DIRECTORY
Inline USING[ BITOR, HighHalf, LongNumber, LowHalf ],
MesaRPC USING[ Conversation, EncryptionKey, InterfaceName,
maxPrincipalLength, maxShortStringLength, Principal,
unencrypted, VersionRange ];
RPCLupine: DEFINITIONS
IMPORTS Inline =
BEGIN
-- Definitions copied across from MesaRPC.mesa for Lupine's benefit --
maxPrincipalLength: CARDINAL = MesaRPC.maxPrincipalLength;
maxShortStringLength: CARDINAL = MesaRPC.maxShortStringLength;
-- StubPkt's are allocated in user-stubs. RPCPkt's are either StubPkt's
-- or packets allocated by the RPC server processes. StubPkt's and
-- RPCPkt's are never seen by the vanilla ethernet
-- driver. StubPktData storage must be aligned to allow the packets to be
-- passed to the ethernet face, and we must correct for the fact that Pup
-- checksums are at the end of the packet. To allocate a packet having
-- up to "n" words of data, declare an array of n+pktOverhead words, then
-- call "GetStubPkt" to obtain the aligned packet. Thus, to allocate
-- space for 250 words, declare:
-- space: ARRAY[1..RPCLupine.pktOverhead+250] OF WORD;
-- pkt: RPCLupine.StubPkt = RPCLupine.GetStubPkt[@space];
-- Horrible! It could be much neater if the compiler supported declaring
-- sequence variables in the local frame. To allocate a maximum size StubPkt,
-- declare:
-- space: ARRAY[1..RPCLupine.pktOverhead+RPCLupine.maxDataLength] OF WORD;
-- pkt: RPCLupine.StubPkt = RPCLupine.GetStubPkt[@space];
Encapsulation: PRIVATE TYPE[7];
-- large enough for all current networks --
Header: PRIVATE TYPE[10+6+4];
-- PUP header + RPC protocol overhead + dispatcher description.
-- Must be aligned to quad-word + 2 --
maxPupWords: PRIVATE CARDINAL =
-- maximum value of length field of Pup packet, in words,
-- as defined in [Maxc]<Pup>PupSpec.press --
266 -- Pup data --
+ 10 -- Pup header --
+ 1 -- Pup checksum --;
encryptionBlockSize: PRIVATE CARDINAL = 4;
SecurityChecksum: PRIVATE TYPE[2];
maxDataLength: CARDINAL =
-- Maximum data words in RPCPkt or StubPkt --
-- The following calculation assumes that the encrypted part of a header
-- is a multiple of encryptionBlockSize --
( ( maxPupWords
- 1 -- Pup checksum --
- SIZE[Header] )
/ encryptionBlockSize --round down--)
* encryptionBlockSize
- SIZE[SecurityChecksum];
DataLength: TYPE = [0..maxDataLength];
pktOverhead: CARDINAL = pktAlign -- wastage for aligning the buffer --
+ SIZE[StubPktData[0]]
+ encryptionBlockSize-1 -- rounding --
+ SIZE[SecurityChecksum]
+ 1 -- Pup checksum --;
pktAlign: PRIVATE WORD = 3B;
-- maximum wastage for quad-word alignment --
StubPkt: TYPE = POINTER TO StubPktData;
RPCPkt: TYPE = LONG StubPkt;
StubPktData: TYPE = MACHINE DEPENDENT RECORD[
-- must be suitably aligned --
convHandle: PRIVATE MesaRPC.Conversation,
encapsulation: PRIVATE Encapsulation,
header: PRIVATE Header, -- Pup/OIS header --
data: SEQUENCE COMPUTED DataLength OF UNSPECIFIED];
GetStubPkt: PROC[ space: POINTER TO UNSPECIFIED]
RETURNS[--pkt:-- StubPkt ] = INLINE
-- returns pointer aligned to quad-word plus one. That
-- causes Ethernet-one encapsulation to start at quad-word (honest!). --
-- i.e. space=0 => result=1,
-- space=1 => result=1,
-- space=2 => result=5,
-- space=3 => result=5.
{ RETURN[ LOOPHOLE[Inline.BITOR[space+2, pktAlign],POINTER]-2 ] };
GetRPCPkt: PROC[ space: LONG POINTER TO UNSPECIFIED]
RETURNS[--pkt:-- RPCPkt ] = INLINE
-- returns pointer aligned to quad-word plus one. That
-- causes Ethernet-one encapsulation to start at quad-word (honest!). --
-- i.e. space=0 => result=1,
-- space=1 => result=1,
-- space=2 => result=5,
-- space=3 => result=5.
-- Unfortunately, the alignment may take us across a 64K boundary!
{ RETURN[ LOOPHOLE[Inline.LongNumber[num[
lowbits: Inline.BITOR[Inline.LowHalf[space+2], pktAlign] - 2,
highbits: Inline.HighHalf[space+2]
]]]] };
-- Binding primitives for use by stubs --
-- Exporter specifies which interface type is being exported, and which
-- instance of that type, and which "version" of that type. The stub
-- should default the interface type to the timestamp of the definitions
-- file bcd. The interface instance defaults to a newly created UID. The
-- version is client-specified, meaning which range of versions this
-- exporter supports.
-- Importer specifies required interface type and instance, and version
-- range. The stub should default the interface type to the timestamp of
-- the definitions file bcd. Interface instance defaults to "any".
-- The version range defaults to "any".
-- The stubProtocol in imports and exports is used to check compatability
-- of stub protocol versions.
ExportHandle: TYPE[SIZE[CARDINAL]];
-- index to table of dispatcher procedures --
ExportInterface: PROC[user: MesaRPC.Principal, password: MesaRPC.EncryptionKey,
interface: MesaRPC.InterfaceName,
dispatcher: Dispatcher,
stubProtocol: MesaRPC.VersionRange,
localOnly: BOOLEAN ← FALSE]
RETURNS[ interfaceInstance: ExportHandle ];
-- Registers export in binding database and local dispatcher table.
-- The user and password provide credentials to update the binding
-- database. If localOnly=TRUE then the network binding database is
-- not updated. --
-- May raise MesaRPC.ExportFailed --
UnexportInterface: PROC[ interfaceInstance: ExportHandle ]
RETURNS[ExportHandle];
-- Removes export from local dispatcher table and binding database. Returns
-- an ExportHandle that will fault if used. --
ImportHandle: TYPE = LONG POINTER TO ImportInstance;
ImportInstance: TYPE;
ImportInterface: PROC[interface: MesaRPC.InterfaceName,
stubProtocol: MesaRPC.VersionRange,
localOnly: BOOLEAN ← FALSE]
RETURNS[ interfaceInstance: ImportHandle ];
-- Searches binding database for exporter of specified interface.
-- If localOnly=TRUE then the import will succeed only if the
-- exporter is on this host. --
-- May raise MesaRPC.ImportFailed --
UnimportInterface: PROC[ interfaceInstance: ImportHandle ]
RETURNS[ ImportHandle ];
-- Releases local representation of binding. Returns an ImportHandle
-- that will fault if used. --
-- Stubs: sending and receiving packets.
-- For a user-stub making a call, the call sequence is:
-- StartCall, SendPrelimPkt*, Call, ReceiveExtraPkt*
-- When a Dispatcher is invoked, its call sequence is:
-- ReceiveExtraPkt*, SendPrelimPkt*
-- The RPC runtime assumes that within one of these sequences, the
-- same stub packet is being used. All state associated with the
-- call is maintained in the packet buffers. StartCall and
-- StartReturn perform no communication, and raise no signals. The
-- other procedures can each raise RPCSignals.CallFailed. All may
-- safely be aborted, if desired.
-- The RPC runtime transports arguments and results from a user-stub
-- to the appropriate dispatcher. Presumably, the first argument
-- packet will specify to the dispatcher which client procedure to
-- call; this is of no concern to the RPC runtime.
StartCall: PROC[callPkt: RPCPkt,
interface: ImportHandle,
localConversation: MesaRPC.Conversation ← MesaRPC.unencrypted];
-- initializes the RPCPkt to specify the call. If localConversation #
-- MesaRPC.unencrypted then the call will be made securely. --
Call: PROC[pkt: RPCPkt, callLength: DataLength,
maxReturnLength: DataLength,
signalHandler: Dispatcher ← NIL]
RETURNS[ returnLength: DataLength,
lastPkt: BOOLEAN];
-- Sends the packet and waits for first return packet. The
-- signalHandler gets invoked if a signal is passed back from
-- the callee machine. --
-- May raise MesaRPC.CallFailed --
SendPrelimPkt: PROC[pkt: RPCPkt, length: DataLength];
-- sends the packet and waits for ack. Packet may then be re-used --
-- Used for sending non-last packets of arguments or results --
-- May raise MesaRPC.CallFailed --
ReceiveExtraPkt: PROC[prevPkt: RPCPkt]
RETURNS[ length: DataLength,
lastPkt: BOOLEAN];
-- Waits for next pkt. Used for receiving
-- non-first packets of arguments or results.
-- Assumes maxlength = maxDataLength --
-- May raise MesaRPC.CallFailed --
Dispatcher: TYPE = PROC[pkt: RPCPkt,
callLength: DataLength, lastPkt: BOOLEAN,
localConversation: MesaRPC.Conversation ]
RETURNS[ returnLength: DataLength ];
-- "pkt" is the first argument packet. This must be passed to
-- any calls of ReceiveExtraPkt or SendPrelimPkt; the stub leaves
-- the last return pkt data in "pkt". "pkt" has maxlength =
-- maxDataLength.
-- The caller of the dispatcher will catch MesaRPC.CallFailed --
StartSignal: PROC[signalPkt: RPCPkt];
-- Called to indicate that a signal is about to be
-- raised in the caller. The stub then calls:
-- SendPrelimPkt*, Call, ReceiveExtraPkt*
-- then RESUME's the signal with the appropriate results.
-- On the caller machine, this looks a call which invokes the
-- signalHandler for his call of "Call".
-- If the signal gets unwound on the caller machine, the call of
-- "Call" gets unwound without the stub being told (except by the
-- "UNWIND" signal). The catch-phrases on the caller machine may of
-- course raise another signal, which comes back to this machine as
-- an invokation of the signalHandler passed to "Call"!
RejectUnbound: ERROR;
-- May be raised by a dispatcher to cause the remote caller to
-- get CallFailed[unbound]. The dispatcher must have sent no
-- result packets before raising this error.
RejectProtocol: ERROR;
-- May be raised by a dispatcher to cause the remote caller to
-- get CallFailed[protocolError]. The dispatcher must have sent
-- no result packets before raising this error.
END.