-- Copyright (C) 1982, 1984 by Xerox Corporation. All rights reserved.
-- MesaRPCLupine.mesa, HGM, 21-Jan-84 20:31:23
-- Interface between stubs and runtime.
-- 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];
MesaRPCLupine: 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.